1/*
2 * Single source autogenerated distributable for Duktape 2.6.0.
3 *
4 * Git commit fffa346eff06a8764b02c31d4336f63a773a95c3 (v2.6.0).
5 * Git branch v2-maintenance.
6 *
7 * See Duktape AUTHORS.rst and LICENSE.txt for copyright and
8 * licensing information.
9 */
10
11/* LICENSE.txt */
12/*
13* ===============
14* Duktape license
15* ===============
16*
17* (http://opensource.org/licenses/MIT)
18*
19* Copyright (c) 2013-2019 by Duktape authors (see AUTHORS.rst)
20*
21* Permission is hereby granted, free of charge, to any person obtaining a copy
22* of this software and associated documentation files (the "Software"), to deal
23* in the Software without restriction, including without limitation the rights
24* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25* copies of the Software, and to permit persons to whom the Software is
26* furnished to do so, subject to the following conditions:
27*
28* The above copyright notice and this permission notice shall be included in
29* all copies or substantial portions of the Software.
30*
31* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37* THE SOFTWARE.
38*/
39
40/* AUTHORS.rst */
41/*
42* ===============
43* Duktape authors
44* ===============
45*
46* Copyright
47* =========
48*
49* Duktape copyrights are held by its authors. Each author has a copyright
50* to their contribution, and agrees to irrevocably license the contribution
51* under the Duktape ``LICENSE.txt``.
52*
53* Authors
54* =======
55*
56* Please include an e-mail address, a link to your GitHub profile, or something
57* similar to allow your contribution to be identified accurately.
58*
59* The following people have contributed code, website contents, or Wiki contents,
60* and agreed to irrevocably license their contributions under the Duktape
61* ``LICENSE.txt`` (in order of appearance):
62*
63* * Sami Vaarala <sami.vaarala@iki.fi>
64* * Niki Dobrev
65* * Andreas \u00d6man <andreas@lonelycoder.com>
66* * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com>
67* * Legimet <legimet.calc@gmail.com>
68* * Karl Skomski <karl@skomski.com>
69* * Bruce Pascoe <fatcerberus1@gmail.com>
70* * Ren\u00e9 Hollander <rene@rene8888.at>
71* * Julien Hamaide (https://github.com/crazyjul)
72* * Sebastian G\u00f6tte (https://github.com/jaseg)
73* * Tomasz Magulski (https://github.com/magul)
74* * \D. Bohdan (https://github.com/dbohdan)
75* * Ond\u0159ej Jirman (https://github.com/megous)
76* * Sa\u00fal Ibarra Corretg\u00e9 <saghul@gmail.com>
77* * Jeremy HU <huxingyi@msn.com>
78* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
79* * Harold Brenes (https://github.com/harold-b)
80* * Oliver Crow (https://github.com/ocrow)
81* * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski)
82* * Brett Vickers (https://github.com/beevik)
83* * Dominik Okwieka (https://github.com/okitec)
84* * Remko Tron\u00e7on (https://el-tramo.be)
85* * Romero Malaquias (rbsm@ic.ufal.br)
86* * Michael Drake <michael.drake@codethink.co.uk>
87* * Steven Don (https://github.com/shdon)
88* * Simon Stone (https://github.com/sstone1)
89* * \J. McC. (https://github.com/jmhmccr)
90* * Jakub Nowakowski (https://github.com/jimvonmoon)
91* * Tommy Nguyen (https://github.com/tn0502)
92* * Fabrice Fontaine (https://github.com/ffontaine)
93* * Christopher Hiller (https://github.com/boneskull)
94* * Gonzalo Diethelm (https://github.com/gonzus)
95* * Michal Kasperek (https://github.com/michalkas)
96* * Andrew Janke (https://github.com/apjanke)
97* * Steve Fan (https://github.com/stevefan1999)
98* * Edward Betts (https://github.com/edwardbetts)
99* * Ozhan Duz (https://github.com/webfolderio)
100* * Akos Kiss (https://github.com/akosthekiss)
101* * TheBrokenRail (https://github.com/TheBrokenRail)
102* * Jesse Doyle (https://github.com/jessedoyle)
103* * Gero Kuehn (https://github.com/dc6jgk)
104* * James Swift (https://github.com/phraemer)
105* * Luis de Bethencourt (https://github.com/luisbg)
106* * Ian Whyman (https://github.com/v00d00)
107* * Rick Sayre (https://github.com/whorfin)
108*
109* Other contributions
110* ===================
111*
112* The following people have contributed something other than code (e.g. reported
113* bugs, provided ideas, etc; roughly in order of appearance):
114*
115* * Greg Burns
116* * Anthony Rabine
117* * Carlos Costa
118* * Aur\u00e9lien Bouilland
119* * Preet Desai (Pris Matic)
120* * judofyr (http://www.reddit.com/user/judofyr)
121* * Jason Woofenden
122* * Micha\u0142 Przyby\u015b
123* * Anthony Howe
124* * Conrad Pankoff
125* * Jim Schimpf
126* * Rajaran Gaunker (https://github.com/zimbabao)
127* * Andreas \u00d6man
128* * Doug Sanden
129* * Josh Engebretson (https://github.com/JoshEngebretson)
130* * Remo Eichenberger (https://github.com/remoe)
131* * Mamod Mehyar (https://github.com/mamod)
132* * David Demelier (https://github.com/markand)
133* * Tim Caswell (https://github.com/creationix)
134* * Mitchell Blank Jr (https://github.com/mitchblank)
135* * https://github.com/yushli
136* * Seo Sanghyeon (https://github.com/sanxiyn)
137* * Han ChoongWoo (https://github.com/tunz)
138* * Joshua Peek (https://github.com/josh)
139* * Bruce E. Pascoe (https://github.com/fatcerberus)
140* * https://github.com/Kelledin
141* * https://github.com/sstruchtrup
142* * Michael Drake (https://github.com/tlsa)
143* * https://github.com/chris-y
144* * Laurent Zubiaur (https://github.com/lzubiaur)
145* * Neil Kolban (https://github.com/nkolban)
146* * Wilhelm Wanecek (https://github.com/wanecek)
147* * Andrew Janke (https://github.com/apjanke)
148* * Unamer (https://github.com/unamer)
149* * Karl Dahlke (eklhad@gmail.com)
150*
151* If you are accidentally missing from this list, send me an e-mail
152* (``sami.vaarala@iki.fi``) and I'll fix the omission.
153*/
154
155#line 1 "duk_replacements.c"
156/*
157 * Replacements for missing platform functions.
158 *
159 * Unlike the originals, fpclassify() and signbit() replacements don't
160 * work on any floating point types, only doubles. The C typing here
161 * mimics the standard prototypes.
162 */
163
164/* #include duk_internal.h */
165#line 1 "duk_internal.h"
166/*
167 * Top-level include file to be used for all (internal) source files.
168 *
169 * Source files should not include individual header files, as they
170 * have not been designed to be individually included.
171 */
172
173#if !defined(DUK_INTERNAL_H_INCLUDED)
174#define DUK_INTERNAL_H_INCLUDED
175
176/*
177 * The 'duktape.h' header provides the public API, but also handles all
178 * compiler and platform specific feature detection, Duktape feature
179 * resolution, inclusion of system headers, etc. These have been merged
180 * because the public API is also dependent on e.g. detecting appropriate
181 * C types which is quite platform/compiler specific especially for a non-C99
182 * build. The public API is also dependent on the resolved feature set.
183 *
184 * Some actions taken by the merged header (such as including system headers)
185 * are not appropriate for building a user application. The define
186 * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
187 * sections depending on what is being built.
188 */
189
190#define DUK_COMPILING_DUKTAPE
191#include "duktape.h"
192
193/*
194 * Duktape includes (other than duk_features.h)
195 *
196 * The header files expect to be included in an order which satisfies header
197 * dependencies correctly (the headers themselves don't include any other
198 * includes). Forward declarations are used to break circular struct/typedef
199 * dependencies.
200 */
201
202/* #include duk_dblunion.h */
203#line 1 "duk_dblunion.h"
204/*
205 * Union to access IEEE double memory representation, indexes for double
206 * memory representation, and some macros for double manipulation.
207 *
208 * Also used by packed duk_tval. Use a union for bit manipulation to
209 * minimize aliasing issues in practice. The C99 standard does not
210 * guarantee that this should work, but it's a very widely supported
211 * practice for low level manipulation.
212 *
213 * IEEE double format summary:
214 *
215 * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
216 * A B C D E F G H
217 *
218 * s sign bit
219 * eee... exponent field
220 * fff... fraction
221 *
222 * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
223 *
224 * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
225 * signaling NaN when the highest bit of the mantissa is zero, and a quiet
226 * NaN when the highest bit is set.
227 *
228 * At least three memory layouts are relevant here:
229 *
230 * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
231 * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
232 * D C B A H G F E Mixed endian (e.g. ARM FPA) DUK_USE_DOUBLE_ME
233 *
234 * Legacy ARM (FPA) is a special case: ARM double values are in mixed
235 * endian format while ARM duk_uint64_t values are in standard little endian
236 * format (H G F E D C B A). When a double is read as a duk_uint64_t
237 * from memory, the register will contain the (logical) value
238 * E F G H A B C D. This requires some special handling below.
239 * See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html.
240 *
241 * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
242 * the logical (big endian) order:
243 *
244 * byte order duk_uint8_t duk_uint16_t duk_uint32_t
245 * BE 01234567 0123 01
246 * LE 76543210 3210 10
247 * ME (ARM) 32107654 1032 01
248 *
249 * Some processors may alter NaN values in a floating point load+store.
250 * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
251 * quiet one. This is catastrophic when NaN space is used in packed
252 * duk_tval values. See: misc/clang_aliasing.c.
253 */
254
255#if !defined(DUK_DBLUNION_H_INCLUDED)
256#define DUK_DBLUNION_H_INCLUDED
257
258/*
259 * Union for accessing double parts, also serves as packed duk_tval
260 */
261
262union duk_double_union {
263 double d;
264 float f[2];
265#if defined(DUK_USE_64BIT_OPS)
266 duk_uint64_t ull[1];
267#endif
268 duk_uint32_t ui[2];
269 duk_uint16_t us[4];
270 duk_uint8_t uc[8];
271#if defined(DUK_USE_PACKED_TVAL)
272 void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
273#endif
274};
275
276typedef union duk_double_union duk_double_union;
277
278/*
279 * Indexes of various types with respect to big endian (logical) layout
280 */
281
282#if defined(DUK_USE_DOUBLE_LE)
283#if defined(DUK_USE_64BIT_OPS)
284#define DUK_DBL_IDX_ULL0 0
285#endif
286#define DUK_DBL_IDX_UI0 1
287#define DUK_DBL_IDX_UI1 0
288#define DUK_DBL_IDX_US0 3
289#define DUK_DBL_IDX_US1 2
290#define DUK_DBL_IDX_US2 1
291#define DUK_DBL_IDX_US3 0
292#define DUK_DBL_IDX_UC0 7
293#define DUK_DBL_IDX_UC1 6
294#define DUK_DBL_IDX_UC2 5
295#define DUK_DBL_IDX_UC3 4
296#define DUK_DBL_IDX_UC4 3
297#define DUK_DBL_IDX_UC5 2
298#define DUK_DBL_IDX_UC6 1
299#define DUK_DBL_IDX_UC7 0
300#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
301#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
302#elif defined(DUK_USE_DOUBLE_BE)
303#if defined(DUK_USE_64BIT_OPS)
304#define DUK_DBL_IDX_ULL0 0
305#endif
306#define DUK_DBL_IDX_UI0 0
307#define DUK_DBL_IDX_UI1 1
308#define DUK_DBL_IDX_US0 0
309#define DUK_DBL_IDX_US1 1
310#define DUK_DBL_IDX_US2 2
311#define DUK_DBL_IDX_US3 3
312#define DUK_DBL_IDX_UC0 0
313#define DUK_DBL_IDX_UC1 1
314#define DUK_DBL_IDX_UC2 2
315#define DUK_DBL_IDX_UC3 3
316#define DUK_DBL_IDX_UC4 4
317#define DUK_DBL_IDX_UC5 5
318#define DUK_DBL_IDX_UC6 6
319#define DUK_DBL_IDX_UC7 7
320#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
321#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
322#elif defined(DUK_USE_DOUBLE_ME)
323#if defined(DUK_USE_64BIT_OPS)
324#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
325#endif
326#define DUK_DBL_IDX_UI0 0
327#define DUK_DBL_IDX_UI1 1
328#define DUK_DBL_IDX_US0 1
329#define DUK_DBL_IDX_US1 0
330#define DUK_DBL_IDX_US2 3
331#define DUK_DBL_IDX_US3 2
332#define DUK_DBL_IDX_UC0 3
333#define DUK_DBL_IDX_UC1 2
334#define DUK_DBL_IDX_UC2 1
335#define DUK_DBL_IDX_UC3 0
336#define DUK_DBL_IDX_UC4 7
337#define DUK_DBL_IDX_UC5 6
338#define DUK_DBL_IDX_UC6 5
339#define DUK_DBL_IDX_UC7 4
340#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
341#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
342#else
343#error internal error
344#endif
345
346/*
347 * Helper macros for reading/writing memory representation parts, used
348 * by duk_numconv.c and duk_tval.h.
349 */
350
351#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
352 (u)->d = (v); \
353 } while (0)
354
355#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
356 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
357 } while (0)
358
359#if defined(DUK_USE_64BIT_OPS)
360#if defined(DUK_USE_DOUBLE_ME)
361#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
362 (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
363 } while (0)
364#else
365#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
366 (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
367 } while (0)
368#endif
369#else /* DUK_USE_64BIT_OPS */
370#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
371 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
372 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
373 } while (0)
374#endif /* DUK_USE_64BIT_OPS */
375
376#define DUK_DBLUNION_SET_LOW32(u,v) do { \
377 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
378 } while (0)
379
380#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
381#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
382#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
383
384#if defined(DUK_USE_64BIT_OPS)
385#if defined(DUK_USE_DOUBLE_ME)
386#define DUK_DBLUNION_SET_UINT64(u,v) do { \
387 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
388 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
389 } while (0)
390#define DUK_DBLUNION_GET_UINT64(u) \
391 ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
392 ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
393#else
394#define DUK_DBLUNION_SET_UINT64(u,v) do { \
395 (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
396 } while (0)
397#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
398#endif
399#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
400#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
401#endif /* DUK_USE_64BIT_OPS */
402
403/*
404 * Double NaN manipulation macros related to NaN normalization needed when
405 * using the packed duk_tval representation. NaN normalization is necessary
406 * to keep double values compatible with the duk_tval format.
407 *
408 * When packed duk_tval is used, the NaN space is used to store pointers
409 * and other tagged values in addition to NaNs. Actual NaNs are normalized
410 * to a specific quiet NaN. The macros below are used by the implementation
411 * to check and normalize NaN values when they might be created. The macros
412 * are essentially NOPs when the non-packed duk_tval representation is used.
413 *
414 * A FULL check is exact and checks all bits. A NOTFULL check is used by
415 * the packed duk_tval and works correctly for all NaNs except those that
416 * begin with 0x7ff0. Since the 'normalized NaN' values used with packed
417 * duk_tval begin with 0x7ff8, the partial check is reliable when packed
418 * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
419 * quiet NaN regardless of its remaining lower bits.
420 *
421 * The ME variant below is specifically for ARM byte order, which has the
422 * feature that while doubles have a mixed byte order (32107654), unsigned
423 * long long values has a little endian byte order (76543210). When writing
424 * a logical double value through a ULL pointer, the 32-bit words need to be
425 * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
426 * This is not full ARM support but suffices for some environments.
427 */
428
429#if defined(DUK_USE_64BIT_OPS)
430#if defined(DUK_USE_DOUBLE_ME)
431/* Macros for 64-bit ops + mixed endian doubles. */
432#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
433 (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
434 } while (0)
435#define DUK__DBLUNION_IS_NAN_FULL(u) \
436 ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
437 ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
438#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
439 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
440#define DUK__DBLUNION_IS_ANYINF(u) \
441 (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
442#define DUK__DBLUNION_IS_POSINF(u) \
443 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
444#define DUK__DBLUNION_IS_NEGINF(u) \
445 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
446#define DUK__DBLUNION_IS_ANYZERO(u) \
447 (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
448#define DUK__DBLUNION_IS_POSZERO(u) \
449 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
450#define DUK__DBLUNION_IS_NEGZERO(u) \
451 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
452#else
453/* Macros for 64-bit ops + big/little endian doubles. */
454#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
455 (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
456 } while (0)
457#define DUK__DBLUNION_IS_NAN_FULL(u) \
458 ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
459 ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
460#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
461 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
462#define DUK__DBLUNION_IS_ANYINF(u) \
463 (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
464#define DUK__DBLUNION_IS_POSINF(u) \
465 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
466#define DUK__DBLUNION_IS_NEGINF(u) \
467 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
468#define DUK__DBLUNION_IS_ANYZERO(u) \
469 (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
470#define DUK__DBLUNION_IS_POSZERO(u) \
471 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
472#define DUK__DBLUNION_IS_NEGZERO(u) \
473 ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
474#endif
475#else /* DUK_USE_64BIT_OPS */
476/* Macros for no 64-bit ops, any endianness. */
477#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
478 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
479 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
480 } while (0)
481#define DUK__DBLUNION_IS_NAN_FULL(u) \
482 ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
483 (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
484 (u)->ui[DUK_DBL_IDX_UI1] != 0))
485#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
486 (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
487 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
488#define DUK__DBLUNION_IS_ANYINF(u) \
489 ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
490 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
491#define DUK__DBLUNION_IS_POSINF(u) \
492 (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
493 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
494#define DUK__DBLUNION_IS_NEGINF(u) \
495 (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
496 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
497#define DUK__DBLUNION_IS_ANYZERO(u) \
498 ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
499 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
500#define DUK__DBLUNION_IS_POSZERO(u) \
501 (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
502 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
503#define DUK__DBLUNION_IS_NEGZERO(u) \
504 (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
505 ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
506#endif /* DUK_USE_64BIT_OPS */
507
508#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
509 (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
510 } while (0)
511
512#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
513 /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
514 ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
515 (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
516
517#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
518 /* E == 0x7ff, F == 8 => normalized NaN */ \
519 ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
520
521#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
522 if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
523 DUK__DBLUNION_SET_NAN_FULL((u)); \
524 } \
525 } while (0)
526
527#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
528 /* Check must be full. */ \
529 if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
530 DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
531 } \
532 } while (0)
533
534/* Concrete macros for NaN handling used by the implementation internals.
535 * Chosen so that they match the duk_tval representation: with a packed
536 * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
537 * these are essentially NOPs.
538 */
539
540#if defined(DUK_USE_PACKED_TVAL)
541#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
542#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
543#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
544#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
545#if 0
546#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
547#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
548#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
549#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
550#endif
551#define DUK_DBLUNION_IS_NORMALIZED(u) \
552 (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
553 DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
554#else /* DUK_USE_PACKED_TVAL */
555#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
556#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
557#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
558#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
559#define DUK_DBLUNION_SET_NAN(u) do { \
560 /* in non-packed representation we don't care about which NaN is used */ \
561 (u)->d = DUK_DOUBLE_NAN; \
562 } while (0)
563#endif /* DUK_USE_PACKED_TVAL */
564
565#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
566#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
567#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
568
569#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
570#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
571#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
572
573/* XXX: native 64-bit byteswaps when available */
574
575/* 64-bit byteswap, same operation independent of target endianness. */
576#define DUK_DBLUNION_BSWAP64(u) do { \
577 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
578 duk__bswaptmp1 = (u)->ui[0]; \
579 duk__bswaptmp2 = (u)->ui[1]; \
580 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
581 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
582 (u)->ui[0] = duk__bswaptmp2; \
583 (u)->ui[1] = duk__bswaptmp1; \
584 } while (0)
585
586/* Byteswap an IEEE double in the duk_double_union from host to network
587 * order. For a big endian target this is a no-op.
588 */
589#if defined(DUK_USE_DOUBLE_LE)
590#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
591 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
592 duk__bswaptmp1 = (u)->ui[0]; \
593 duk__bswaptmp2 = (u)->ui[1]; \
594 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
595 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
596 (u)->ui[0] = duk__bswaptmp2; \
597 (u)->ui[1] = duk__bswaptmp1; \
598 } while (0)
599#elif defined(DUK_USE_DOUBLE_ME)
600#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
601 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
602 duk__bswaptmp1 = (u)->ui[0]; \
603 duk__bswaptmp2 = (u)->ui[1]; \
604 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
605 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
606 (u)->ui[0] = duk__bswaptmp1; \
607 (u)->ui[1] = duk__bswaptmp2; \
608 } while (0)
609#elif defined(DUK_USE_DOUBLE_BE)
610#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
611#else
612#error internal error, double endianness insane
613#endif
614
615/* Reverse operation is the same. */
616#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
617
618/* Some sign bit helpers. */
619#if defined(DUK_USE_64BIT_OPS)
620#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
621#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
622#else
623#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
624#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
625#endif
626
627#endif /* DUK_DBLUNION_H_INCLUDED */
628/* #include duk_fltunion.h */
629#line 1 "duk_fltunion.h"
630/*
631 * Union to access IEEE float memory representation.
632 */
633
634#if !defined(DUK_FLTUNION_H_INCLUDED)
635#define DUK_FLTUNION_H_INCLUDED
636
637/* #include duk_internal.h -> already included */
638
639union duk_float_union {
640 float f;
641 duk_uint32_t ui[1];
642 duk_uint16_t us[2];
643 duk_uint8_t uc[4];
644};
645
646typedef union duk_float_union duk_float_union;
647
648#if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME)
649#define DUK_FLT_IDX_UI0 0
650#define DUK_FLT_IDX_US0 1
651#define DUK_FLT_IDX_US1 0
652#define DUK_FLT_IDX_UC0 3
653#define DUK_FLT_IDX_UC1 2
654#define DUK_FLT_IDX_UC2 1
655#define DUK_FLT_IDX_UC3 0
656#elif defined(DUK_USE_DOUBLE_BE)
657#define DUK_FLT_IDX_UI0 0
658#define DUK_FLT_IDX_US0 0
659#define DUK_FLT_IDX_US1 1
660#define DUK_FLT_IDX_UC0 0
661#define DUK_FLT_IDX_UC1 1
662#define DUK_FLT_IDX_UC2 2
663#define DUK_FLT_IDX_UC3 3
664#else
665#error internal error
666#endif
667
668#endif /* DUK_FLTUNION_H_INCLUDED */
669/* #include duk_replacements.h */
670#line 1 "duk_replacements.h"
671#if !defined(DUK_REPLACEMENTS_H_INCLUDED)
672#define DUK_REPLACEMENTS_H_INCLUDED
673
674#if !defined(DUK_SINGLE_FILE)
675#if defined(DUK_USE_COMPUTED_INFINITY)
676DUK_INTERNAL_DECL double duk_computed_infinity;
677#endif
678#if defined(DUK_USE_COMPUTED_NAN)
679DUK_INTERNAL_DECL double duk_computed_nan;
680#endif
681#endif /* !DUK_SINGLE_FILE */
682
683#if defined(DUK_USE_REPL_FPCLASSIFY)
684DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
685#endif
686#if defined(DUK_USE_REPL_SIGNBIT)
687DUK_INTERNAL_DECL int duk_repl_signbit(double x);
688#endif
689#if defined(DUK_USE_REPL_ISFINITE)
690DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
691#endif
692#if defined(DUK_USE_REPL_ISNAN)
693DUK_INTERNAL_DECL int duk_repl_isnan(double x);
694#endif
695#if defined(DUK_USE_REPL_ISINF)
696DUK_INTERNAL_DECL int duk_repl_isinf(double x);
697#endif
698
699#endif /* DUK_REPLACEMENTS_H_INCLUDED */
700/* #include duk_jmpbuf.h */
701#line 1 "duk_jmpbuf.h"
702/*
703 * Wrapper for jmp_buf.
704 *
705 * This is used because jmp_buf is an array type for backward compatibility.
706 * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
707 * behave more intuitively.
708 *
709 * http://en.wikipedia.org/wiki/Setjmp.h#Member_types
710 */
711
712#if !defined(DUK_JMPBUF_H_INCLUDED)
713#define DUK_JMPBUF_H_INCLUDED
714
715#if defined(DUK_USE_CPP_EXCEPTIONS)
716struct duk_jmpbuf {
717 duk_small_int_t dummy; /* unused */
718};
719#else
720struct duk_jmpbuf {
721 DUK_JMPBUF_TYPE jb;
722};
723#endif
724
725#endif /* DUK_JMPBUF_H_INCLUDED */
726/* #include duk_exception.h */
727#line 1 "duk_exception.h"
728/*
729 * Exceptions for Duktape internal throws when C++ exceptions are used
730 * for long control transfers.
731 */
732
733#if !defined(DUK_EXCEPTION_H_INCLUDED)
734#define DUK_EXCEPTION_H_INCLUDED
735
736#if defined(DUK_USE_CPP_EXCEPTIONS)
737/* Internal exception used as a setjmp-longjmp replacement. User code should
738 * NEVER see or catch this exception, so it doesn't inherit from any base
739 * class which should minimize the chance of user code accidentally catching
740 * the exception.
741 */
742class duk_internal_exception {
743 /* intentionally empty */
744};
745
746/* Fatal error, thrown as a specific C++ exception with C++ exceptions
747 * enabled. It is unsafe to continue; doing so may cause crashes or memory
748 * leaks. This is intended to be either uncaught, or caught by user code
749 * aware of the "unsafe to continue" semantics.
750 */
751class duk_fatal_exception : public virtual std::runtime_error {
752 public:
753 duk_fatal_exception(const char *message) : std::runtime_error(message) {}
754};
755#endif
756
757#endif /* DUK_EXCEPTION_H_INCLUDED */
758/* #include duk_forwdecl.h */
759#line 1 "duk_forwdecl.h"
760/*
761 * Forward declarations for all Duktape structures.
762 */
763
764#if !defined(DUK_FORWDECL_H_INCLUDED)
765#define DUK_FORWDECL_H_INCLUDED
766
767/*
768 * Forward declarations
769 */
770
771#if defined(DUK_USE_CPP_EXCEPTIONS)
772class duk_internal_exception;
773#else
774struct duk_jmpbuf;
775#endif
776
777/* duk_tval intentionally skipped */
778struct duk_heaphdr;
779struct duk_heaphdr_string;
780struct duk_harray;
781struct duk_hstring;
782struct duk_hstring_external;
783struct duk_hobject;
784struct duk_hcompfunc;
785struct duk_hnatfunc;
786struct duk_hboundfunc;
787struct duk_hthread;
788struct duk_hbufobj;
789struct duk_hdecenv;
790struct duk_hobjenv;
791struct duk_hproxy;
792struct duk_hbuffer;
793struct duk_hbuffer_fixed;
794struct duk_hbuffer_dynamic;
795struct duk_hbuffer_external;
796
797struct duk_propaccessor;
798union duk_propvalue;
799struct duk_propdesc;
800
801struct duk_heap;
802struct duk_breakpoint;
803
804struct duk_activation;
805struct duk_catcher;
806struct duk_ljstate;
807struct duk_strcache_entry;
808struct duk_litcache_entry;
809struct duk_strtab_entry;
810
811#if defined(DUK_USE_DEBUG)
812struct duk_fixedbuffer;
813#endif
814
815struct duk_bitdecoder_ctx;
816struct duk_bitencoder_ctx;
817struct duk_bufwriter_ctx;
818
819struct duk_token;
820struct duk_re_token;
821struct duk_lexer_point;
822struct duk_lexer_ctx;
823struct duk_lexer_codepoint;
824
825struct duk_compiler_instr;
826struct duk_compiler_func;
827struct duk_compiler_ctx;
828
829struct duk_re_matcher_ctx;
830struct duk_re_compiler_ctx;
831
832#if defined(DUK_USE_CPP_EXCEPTIONS)
833/* no typedef */
834#else
835typedef struct duk_jmpbuf duk_jmpbuf;
836#endif
837
838/* duk_tval intentionally skipped */
839typedef struct duk_heaphdr duk_heaphdr;
840typedef struct duk_heaphdr_string duk_heaphdr_string;
841typedef struct duk_harray duk_harray;
842typedef struct duk_hstring duk_hstring;
843typedef struct duk_hstring_external duk_hstring_external;
844typedef struct duk_hobject duk_hobject;
845typedef struct duk_hcompfunc duk_hcompfunc;
846typedef struct duk_hnatfunc duk_hnatfunc;
847typedef struct duk_hboundfunc duk_hboundfunc;
848typedef struct duk_hthread duk_hthread;
849typedef struct duk_hbufobj duk_hbufobj;
850typedef struct duk_hdecenv duk_hdecenv;
851typedef struct duk_hobjenv duk_hobjenv;
852typedef struct duk_hproxy duk_hproxy;
853typedef struct duk_hbuffer duk_hbuffer;
854typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
855typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
856typedef struct duk_hbuffer_external duk_hbuffer_external;
857
858typedef struct duk_propaccessor duk_propaccessor;
859typedef union duk_propvalue duk_propvalue;
860typedef struct duk_propdesc duk_propdesc;
861
862typedef struct duk_heap duk_heap;
863typedef struct duk_breakpoint duk_breakpoint;
864
865typedef struct duk_activation duk_activation;
866typedef struct duk_catcher duk_catcher;
867typedef struct duk_ljstate duk_ljstate;
868typedef struct duk_strcache_entry duk_strcache_entry;
869typedef struct duk_litcache_entry duk_litcache_entry;
870typedef struct duk_strtab_entry duk_strtab_entry;
871
872#if defined(DUK_USE_DEBUG)
873typedef struct duk_fixedbuffer duk_fixedbuffer;
874#endif
875
876typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
877typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
878typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
879
880typedef struct duk_token duk_token;
881typedef struct duk_re_token duk_re_token;
882typedef struct duk_lexer_point duk_lexer_point;
883typedef struct duk_lexer_ctx duk_lexer_ctx;
884typedef struct duk_lexer_codepoint duk_lexer_codepoint;
885
886typedef struct duk_compiler_instr duk_compiler_instr;
887typedef struct duk_compiler_func duk_compiler_func;
888typedef struct duk_compiler_ctx duk_compiler_ctx;
889
890typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
891typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
892
893#endif /* DUK_FORWDECL_H_INCLUDED */
894/* #include duk_tval.h */
895#line 1 "duk_tval.h"
896/*
897 * Tagged type definition (duk_tval) and accessor macros.
898 *
899 * Access all fields through the accessor macros, as the representation
900 * is quite tricky.
901 *
902 * There are two packed type alternatives: an 8-byte representation
903 * based on an IEEE double (preferred for compactness), and a 12-byte
904 * representation (portability). The latter is needed also in e.g.
905 * 64-bit environments (it usually pads to 16 bytes per value).
906 *
907 * Selecting the tagged type format involves many trade-offs (memory
908 * use, size and performance of generated code, portability, etc).
909 *
910 * NB: because macro arguments are often expressions, macros should
911 * avoid evaluating their argument more than once.
912 */
913
914#if !defined(DUK_TVAL_H_INCLUDED)
915#define DUK_TVAL_H_INCLUDED
916
917/* sanity */
918#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
919#error unsupported: cannot determine byte order variant
920#endif
921
922#if defined(DUK_USE_PACKED_TVAL)
923/* ======================================================================== */
924
925/*
926 * Packed 8-byte representation
927 */
928
929/* use duk_double_union as duk_tval directly */
930typedef union duk_double_union duk_tval;
931typedef struct {
932 duk_uint16_t a;
933 duk_uint16_t b;
934 duk_uint16_t c;
935 duk_uint16_t d;
936} duk_tval_unused;
937
938/* tags */
939#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
940/* avoid tag 0xfff0, no risk of confusion with negative infinity */
941#define DUK_TAG_MIN 0xfff1UL
942#if defined(DUK_USE_FASTINT)
943#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
944#endif
945#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
946#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
947#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
948#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
949/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
950#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
951#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
952#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
953#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
954#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
955#define DUK_TAG_MAX 0xfffaUL
956
957/* for convenience */
958#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
959#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
960
961#define DUK_TVAL_IS_VALID_TAG(tv) \
962 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
963
964/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */
965#define DUK_TVAL_UNUSED_INITIALIZER() \
966 { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED }
967
968/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
969#if defined(DUK_USE_64BIT_OPS)
970#if defined(DUK_USE_DOUBLE_ME)
971#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
972 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
973 } while (0)
974#else
975#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
976 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
977 } while (0)
978#endif
979#else /* DUK_USE_64BIT_OPS */
980#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
981 duk_tval *duk__tv; \
982 duk__tv = (tv); \
983 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
984 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
985 } while (0)
986#endif /* DUK_USE_64BIT_OPS */
987
988#if defined(DUK_USE_64BIT_OPS)
989/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
990#if defined(DUK_USE_DOUBLE_ME)
991#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
992 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
993 ((duk_uint64_t) (flags)) | \
994 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
995 } while (0)
996#else
997#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
998 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
999 (((duk_uint64_t) (flags)) << 32) | \
1000 ((duk_uint64_t) (duk_uint32_t) (fp)); \
1001 } while (0)
1002#endif
1003#else /* DUK_USE_64BIT_OPS */
1004#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
1005 duk_tval *duk__tv; \
1006 duk__tv = (tv); \
1007 duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
1008 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
1009 } while (0)
1010#endif /* DUK_USE_64BIT_OPS */
1011
1012#if defined(DUK_USE_FASTINT)
1013/* Note: masking is done for 'i' to deal with negative numbers correctly */
1014#if defined(DUK_USE_DOUBLE_ME)
1015#define DUK__TVAL_SET_I48(tv,i) do { \
1016 duk_tval *duk__tv; \
1017 duk__tv = (tv); \
1018 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
1019 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
1020 } while (0)
1021#define DUK__TVAL_SET_U32(tv,i) do { \
1022 duk_tval *duk__tv; \
1023 duk__tv = (tv); \
1024 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
1025 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
1026 } while (0)
1027#else
1028#define DUK__TVAL_SET_I48(tv,i) do { \
1029 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \
1030 } while (0)
1031#define DUK__TVAL_SET_U32(tv,i) do { \
1032 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
1033 } while (0)
1034#endif
1035
1036/* This needs to go through a cast because sign extension is needed. */
1037#define DUK__TVAL_SET_I32(tv,i) do { \
1038 duk_int64_t duk__tmp = (duk_int64_t) (i); \
1039 DUK_TVAL_SET_I48((tv), duk__tmp); \
1040 } while (0)
1041
1042/* XXX: Clumsy sign extend and masking of 16 topmost bits. */
1043#if defined(DUK_USE_DOUBLE_ME)
1044#define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
1045#else
1046#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
1047#endif
1048#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1])
1049#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1])
1050#endif /* DUK_USE_FASTINT */
1051
1052#define DUK_TVAL_SET_UNDEFINED(tv) do { \
1053 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
1054 } while (0)
1055#define DUK_TVAL_SET_UNUSED(tv) do { \
1056 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
1057 } while (0)
1058#define DUK_TVAL_SET_NULL(tv) do { \
1059 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
1060 } while (0)
1061
1062#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
1063
1064#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv))
1065
1066/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
1067#if defined(DUK_USE_FASTINT)
1068#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
1069 duk_double_t duk__dblval; \
1070 duk__dblval = (d); \
1071 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
1072 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
1073 } while (0)
1074#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i))
1075#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i))
1076#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i))
1077#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d))
1078#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d))
1079#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
1080#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
1081 duk_tval *duk__tv; \
1082 duk_double_t duk__d; \
1083 duk__tv = (tv); \
1084 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1085 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1086 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
1087 } \
1088 } while (0)
1089#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
1090 duk_tval *duk__tv; \
1091 duk_double_t duk__d; \
1092 duk__tv = (tv); \
1093 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1094 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1095 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
1096 } \
1097 } while (0)
1098#else /* DUK_USE_FASTINT */
1099#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
1100 duk_double_t duk__dblval; \
1101 duk__dblval = (d); \
1102 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
1103 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
1104 } while (0)
1105#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */
1106#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
1107#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
1108#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
1109#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
1110#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
1111#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
1112#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
1113#endif /* DUK_USE_FASTINT */
1114
1115#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */
1116
1117#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags))
1118#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING)
1119#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT)
1120#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER)
1121#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER)
1122
1123#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
1124
1125/* getters */
1126#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1])
1127#if defined(DUK_USE_FASTINT)
1128#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
1129#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv))
1130#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv))
1131#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv))
1132#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv))
1133#else
1134#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d)
1135#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
1136#endif
1137#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
1138 (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
1139 (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
1140 } while (0)
1141#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
1142#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
1143#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
1144#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
1145#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
1146#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1])
1147#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1])
1148
1149/* decoding */
1150#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0])
1151
1152#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED)
1153#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED)
1154#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL)
1155#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN)
1156#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
1157#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
1158#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC)
1159#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING)
1160#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT)
1161#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER)
1162#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER)
1163#if defined(DUK_USE_FASTINT)
1164/* 0xfff0 is -Infinity */
1165#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
1166#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT)
1167#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL)
1168#else
1169#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
1170#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
1171#endif
1172
1173/* This is performance critical because it appears in every DECREF. */
1174#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING)
1175
1176#if defined(DUK_USE_FASTINT)
1177DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
1178#endif
1179
1180#else /* DUK_USE_PACKED_TVAL */
1181/* ======================================================================== */
1182
1183/*
1184 * Portable 12-byte representation
1185 */
1186
1187/* Note: not initializing all bytes is normally not an issue: Duktape won't
1188 * read or use the uninitialized bytes so valgrind won't issue warnings.
1189 * In some special cases a harmless valgrind warning may be issued though.
1190 * For example, the DumpHeap debugger command writes out a compiled function's
1191 * 'data' area as is, including any uninitialized bytes, which causes a
1192 * valgrind warning.
1193 */
1194
1195typedef struct duk_tval_struct duk_tval;
1196
1197struct duk_tval_struct {
1198 duk_small_uint_t t;
1199 duk_small_uint_t v_extra;
1200 union {
1201 duk_double_t d;
1202 duk_small_int_t i;
1203#if defined(DUK_USE_FASTINT)
1204 duk_int64_t fi; /* if present, forces 16-byte duk_tval */
1205#endif
1206 void *voidptr;
1207 duk_hstring *hstring;
1208 duk_hobject *hobject;
1209 duk_hcompfunc *hcompfunc;
1210 duk_hnatfunc *hnatfunc;
1211 duk_hthread *hthread;
1212 duk_hbuffer *hbuffer;
1213 duk_heaphdr *heaphdr;
1214 duk_c_function lightfunc;
1215 } v;
1216};
1217
1218typedef struct {
1219 duk_small_uint_t t;
1220 duk_small_uint_t v_extra;
1221 /* The rest of the fields don't matter except for debug dumps and such
1222 * for which a partial initializer may trigger out-ot-bounds memory
1223 * reads. Include a double field which is usually as large or larger
1224 * than pointers (not always however).
1225 */
1226 duk_double_t d;
1227} duk_tval_unused;
1228
1229#define DUK_TVAL_UNUSED_INITIALIZER() \
1230 { DUK_TAG_UNUSED, 0, 0.0 }
1231
1232#define DUK_TAG_MIN 0
1233#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */
1234#if defined(DUK_USE_FASTINT)
1235#define DUK_TAG_FASTINT 1
1236#endif
1237#define DUK_TAG_UNDEFINED 2
1238#define DUK_TAG_NULL 3
1239#define DUK_TAG_BOOLEAN 4
1240#define DUK_TAG_POINTER 5
1241#define DUK_TAG_LIGHTFUNC 6
1242#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
1243#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
1244#define DUK_TAG_OBJECT 9
1245#define DUK_TAG_BUFFER 10
1246#define DUK_TAG_MAX 10
1247
1248#define DUK_TVAL_IS_VALID_TAG(tv) \
1249 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
1250
1251/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code
1252 * to support the 8-byte representation. Further, it is a non-heap-allocated
1253 * type so it should come before DUK_TAG_STRING. Finally, it should not break
1254 * the tag value ranges covered by case-clauses in a switch-case.
1255 */
1256
1257/* setters */
1258#define DUK_TVAL_SET_UNDEFINED(tv) do { \
1259 duk_tval *duk__tv; \
1260 duk__tv = (tv); \
1261 duk__tv->t = DUK_TAG_UNDEFINED; \
1262 } while (0)
1263
1264#define DUK_TVAL_SET_UNUSED(tv) do { \
1265 duk_tval *duk__tv; \
1266 duk__tv = (tv); \
1267 duk__tv->t = DUK_TAG_UNUSED; \
1268 } while (0)
1269
1270#define DUK_TVAL_SET_NULL(tv) do { \
1271 duk_tval *duk__tv; \
1272 duk__tv = (tv); \
1273 duk__tv->t = DUK_TAG_NULL; \
1274 } while (0)
1275
1276#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
1277 duk_tval *duk__tv; \
1278 duk__tv = (tv); \
1279 duk__tv->t = DUK_TAG_BOOLEAN; \
1280 duk__tv->v.i = (duk_small_int_t) (val); \
1281 } while (0)
1282
1283#if defined(DUK_USE_FASTINT)
1284#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
1285 duk_tval *duk__tv; \
1286 duk_double_t duk__dblval; \
1287 duk__dblval = (val); \
1288 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
1289 duk__tv = (tv); \
1290 duk__tv->t = DUK_TAG_NUMBER; \
1291 duk__tv->v.d = duk__dblval; \
1292 } while (0)
1293#define DUK_TVAL_SET_I48(tv,val) do { \
1294 duk_tval *duk__tv; \
1295 duk__tv = (tv); \
1296 duk__tv->t = DUK_TAG_FASTINT; \
1297 duk__tv->v.fi = (val); \
1298 } while (0)
1299#define DUK_TVAL_SET_U32(tv,val) do { \
1300 duk_tval *duk__tv; \
1301 duk__tv = (tv); \
1302 duk__tv->t = DUK_TAG_FASTINT; \
1303 duk__tv->v.fi = (duk_int64_t) (val); \
1304 } while (0)
1305#define DUK_TVAL_SET_I32(tv,val) do { \
1306 duk_tval *duk__tv; \
1307 duk__tv = (tv); \
1308 duk__tv->t = DUK_TAG_FASTINT; \
1309 duk__tv->v.fi = (duk_int64_t) (val); \
1310 } while (0)
1311#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
1312 duk_tval_set_number_chkfast_fast((tv), (d))
1313#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
1314 duk_tval_set_number_chkfast_slow((tv), (d))
1315#define DUK_TVAL_SET_NUMBER(tv,val) \
1316 DUK_TVAL_SET_DOUBLE((tv), (val))
1317#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
1318 duk_tval *duk__tv; \
1319 duk_double_t duk__d; \
1320 duk__tv = (tv); \
1321 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1322 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1323 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
1324 } \
1325 } while (0)
1326#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
1327 duk_tval *duk__tv; \
1328 duk_double_t duk__d; \
1329 duk__tv = (tv); \
1330 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1331 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1332 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
1333 } \
1334 } while (0)
1335#else /* DUK_USE_FASTINT */
1336#define DUK_TVAL_SET_DOUBLE(tv,d) \
1337 DUK_TVAL_SET_NUMBER((tv), (d))
1338#define DUK_TVAL_SET_I48(tv,val) \
1339 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
1340#define DUK_TVAL_SET_U32(tv,val) \
1341 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
1342#define DUK_TVAL_SET_I32(tv,val) \
1343 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
1344#define DUK_TVAL_SET_NUMBER(tv,val) do { \
1345 duk_tval *duk__tv; \
1346 duk_double_t duk__dblval; \
1347 duk__dblval = (val); \
1348 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
1349 duk__tv = (tv); \
1350 duk__tv->t = DUK_TAG_NUMBER; \
1351 duk__tv->v.d = duk__dblval; \
1352 } while (0)
1353#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
1354 DUK_TVAL_SET_NUMBER((tv), (d))
1355#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
1356 DUK_TVAL_SET_NUMBER((tv), (d))
1357#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
1358#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
1359#endif /* DUK_USE_FASTINT */
1360
1361#define DUK_TVAL_SET_FASTINT(tv,i) \
1362 DUK_TVAL_SET_I48((tv), (i)) /* alias */
1363
1364#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
1365 duk_tval *duk__tv; \
1366 duk__tv = (tv); \
1367 duk__tv->t = DUK_TAG_POINTER; \
1368 duk__tv->v.voidptr = (hptr); \
1369 } while (0)
1370
1371#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
1372 duk_tval *duk__tv; \
1373 duk__tv = (tv); \
1374 duk__tv->t = DUK_TAG_LIGHTFUNC; \
1375 duk__tv->v_extra = (flags); \
1376 duk__tv->v.lightfunc = (duk_c_function) (fp); \
1377 } while (0)
1378
1379#define DUK_TVAL_SET_STRING(tv,hptr) do { \
1380 duk_tval *duk__tv; \
1381 duk__tv = (tv); \
1382 duk__tv->t = DUK_TAG_STRING; \
1383 duk__tv->v.hstring = (hptr); \
1384 } while (0)
1385
1386#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
1387 duk_tval *duk__tv; \
1388 duk__tv = (tv); \
1389 duk__tv->t = DUK_TAG_OBJECT; \
1390 duk__tv->v.hobject = (hptr); \
1391 } while (0)
1392
1393#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
1394 duk_tval *duk__tv; \
1395 duk__tv = (tv); \
1396 duk__tv->t = DUK_TAG_BUFFER; \
1397 duk__tv->v.hbuffer = (hptr); \
1398 } while (0)
1399
1400#define DUK_TVAL_SET_NAN(tv) do { \
1401 /* in non-packed representation we don't care about which NaN is used */ \
1402 duk_tval *duk__tv; \
1403 duk__tv = (tv); \
1404 duk__tv->t = DUK_TAG_NUMBER; \
1405 duk__tv->v.d = DUK_DOUBLE_NAN; \
1406 } while (0)
1407
1408#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
1409
1410/* getters */
1411#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i)
1412#if defined(DUK_USE_FASTINT)
1413#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
1414#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
1415#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
1416#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
1417#if 0
1418#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
1419 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
1420 DUK_TVAL_GET_DOUBLE((tv)))
1421#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
1422#else
1423/* This seems reasonable overall. */
1424#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
1425 duk_tval_get_number_unpacked_fastint((tv)) : \
1426 DUK_TVAL_GET_DOUBLE((tv)))
1427#endif
1428#else
1429#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
1430#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
1431#endif /* DUK_USE_FASTINT */
1432#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
1433#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
1434 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
1435 (out_fp) = (tv)->v.lightfunc; \
1436 } while (0)
1437#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
1438#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra))
1439#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
1440#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
1441#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
1442#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
1443
1444/* decoding */
1445#define DUK_TVAL_GET_TAG(tv) ((tv)->t)
1446#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
1447#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
1448#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
1449#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
1450#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
1451#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
1452#if defined(DUK_USE_FASTINT)
1453#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER)
1454#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
1455#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \
1456 (tv)->t == DUK_TAG_FASTINT)
1457#else
1458#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER)
1459#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
1460#endif /* DUK_USE_FASTINT */
1461#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
1462#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
1463#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
1464#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
1465#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
1466
1467/* This is performance critical because it's needed for every DECREF.
1468 * Take advantage of the fact that the first heap allocated tag is 8,
1469 * so that bit 3 is set for all heap allocated tags (and never set for
1470 * non-heap-allocated tags).
1471 */
1472#if 0
1473#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
1474#endif
1475#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
1476
1477#if defined(DUK_USE_FASTINT)
1478#if 0
1479DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
1480#endif
1481DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
1482#endif
1483
1484#endif /* DUK_USE_PACKED_TVAL */
1485
1486/*
1487 * Convenience (independent of representation)
1488 */
1489
1490#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1)
1491#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0)
1492
1493#define DUK_TVAL_STRING_IS_SYMBOL(tv) \
1494 DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv)))
1495
1496/* Lightfunc flags packing and unpacking. */
1497/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##.
1498 * Avoid signed shifts due to portability limitations.
1499 */
1500#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
1501 ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
1502#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
1503 (((lf_flags) >> 4) & 0x0fU)
1504#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
1505 ((lf_flags) & 0x0fU)
1506#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
1507 ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs)
1508
1509#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
1510#define DUK_LFUNC_NARGS_MIN 0x00
1511#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
1512#define DUK_LFUNC_LENGTH_MIN 0x00
1513#define DUK_LFUNC_LENGTH_MAX 0x0f
1514#define DUK_LFUNC_MAGIC_MIN (-0x80)
1515#define DUK_LFUNC_MAGIC_MAX 0x7f
1516
1517/* fastint constants etc */
1518#if defined(DUK_USE_FASTINT)
1519#define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000))
1520#define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff))
1521#define DUK_FASTINT_BITS 48
1522
1523DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
1524DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
1525#endif
1526
1527#if defined(DUK_USE_ASSERTIONS)
1528DUK_INTERNAL_DECL void duk_tval_assert_valid(duk_tval *tv);
1529#define DUK_TVAL_ASSERT_VALID(tv) do { duk_tval_assert_valid((tv)); } while (0)
1530#else
1531#define DUK_TVAL_ASSERT_VALID(tv) do {} while (0)
1532#endif
1533
1534#endif /* DUK_TVAL_H_INCLUDED */
1535/* #include duk_builtins.h */
1536#line 1 "duk_builtins.h"
1537/*
1538 * Automatically generated by genbuiltins.py, do not edit!
1539 */
1540
1541#if !defined(DUK_BUILTINS_H_INCLUDED)
1542#define DUK_BUILTINS_H_INCLUDED
1543
1544#if defined(DUK_USE_ROM_STRINGS)
1545#error ROM support not enabled, rerun configure.py with --rom-support
1546#else /* DUK_USE_ROM_STRINGS */
1547#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
1548#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
1549#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
1550#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
1551#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
1552#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
1553#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */
1554#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
1555#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
1556#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */
1557#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
1558#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
1559#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */
1560#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
1561#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
1562#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */
1563#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
1564#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
1565#define DUK_STRIDX_UC_ARRAY 6 /* 'Array' */
1566#define DUK_HEAP_STRING_UC_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARRAY)
1567#define DUK_HTHREAD_STRING_UC_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARRAY)
1568#define DUK_STRIDX_UC_STRING 7 /* 'String' */
1569#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
1570#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
1571#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */
1572#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
1573#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
1574#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */
1575#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
1576#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
1577#define DUK_STRIDX_UC_DATE 10 /* 'Date' */
1578#define DUK_HEAP_STRING_UC_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_DATE)
1579#define DUK_HTHREAD_STRING_UC_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_DATE)
1580#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */
1581#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
1582#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
1583#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */
1584#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
1585#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
1586#define DUK_STRIDX_MATH 13 /* 'Math' */
1587#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
1588#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
1589#define DUK_STRIDX_JSON 14 /* 'JSON' */
1590#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
1591#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
1592#define DUK_STRIDX_EMPTY_STRING 15 /* '' */
1593#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
1594#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
1595#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */
1596#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
1597#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
1598#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */
1599#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
1600#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
1601#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */
1602#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
1603#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
1604#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */
1605#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
1606#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
1607#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */
1608#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1609#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1610#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */
1611#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
1612#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
1613#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */
1614#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
1615#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
1616#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */
1617#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
1618#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
1619#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */
1620#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
1621#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
1622#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */
1623#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
1624#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
1625#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */
1626#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
1627#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
1628#define DUK_STRIDX_GLOBAL 27 /* 'global' */
1629#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
1630#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
1631#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */
1632#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
1633#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
1634#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */
1635#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
1636#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
1637#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */
1638#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
1639#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
1640#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */
1641#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
1642#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
1643#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */
1644#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
1645#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
1646#define DUK_STRIDX_EVAL 33 /* 'eval' */
1647#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
1648#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
1649#define DUK_STRIDX_VALUE 34 /* 'value' */
1650#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
1651#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
1652#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
1653#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
1654#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
1655#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
1656#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
1657#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
1658#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
1659#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
1660#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
1661#define DUK_STRIDX_JOIN 38 /* 'join' */
1662#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
1663#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
1664#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
1665#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
1666#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
1667#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
1668#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
1669#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
1670#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
1671#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
1672#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
1673#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
1674#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
1675#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
1676#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
1677#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
1678#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
1679#define DUK_STRIDX_SOURCE 44 /* 'source' */
1680#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
1681#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
1682#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
1683#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
1684#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
1685#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
1686#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
1687#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
1688#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
1689#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
1690#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
1691#define DUK_STRIDX_FLAGS 48 /* 'flags' */
1692#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
1693#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
1694#define DUK_STRIDX_INDEX 49 /* 'index' */
1695#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
1696#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
1697#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
1698#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
1699#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
1700#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
1701#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
1702#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
1703#define DUK_STRIDX_MESSAGE 52 /* 'message' */
1704#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
1705#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
1706#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
1707#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
1708#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
1709#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
1710#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
1711#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
1712#define DUK_STRIDX_LC_STRING 55 /* 'string' */
1713#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
1714#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
1715#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */
1716#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
1717#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
1718#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */
1719#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
1720#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
1721#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */
1722#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
1723#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
1724#define DUK_STRIDX_NAN 59 /* 'NaN' */
1725#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
1726#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
1727#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */
1728#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
1729#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
1730#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */
1731#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
1732#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
1733#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */
1734#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
1735#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
1736#define DUK_STRIDX_COMMA 63 /* ',' */
1737#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
1738#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
1739#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
1740#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
1741#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
1742#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
1743#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
1744#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
1745#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
1746#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
1747#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
1748#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
1749#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
1750#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
1751#define DUK_STRIDX_CALLEE 68 /* 'callee' */
1752#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
1753#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
1754#define DUK_STRIDX_CALLER 69 /* 'caller' */
1755#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
1756#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
1757#define DUK_STRIDX_APPLY 70 /* 'apply' */
1758#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
1759#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
1760#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */
1761#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
1762#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
1763#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
1764#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
1765#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
1766#define DUK_STRIDX_GET 73 /* 'get' */
1767#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
1768#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
1769#define DUK_STRIDX_HAS 74 /* 'has' */
1770#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
1771#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
1772#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
1773#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
1774#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
1775#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */
1776#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
1777#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
1778#define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */
1779#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
1780#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
1781#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */
1782#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
1783#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
1784#define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */
1785#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
1786#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
1787#define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */
1788#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
1789#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
1790#define DUK_STRIDX___PROTO__ 81 /* '__proto__' */
1791#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
1792#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
1793#define DUK_STRIDX_TO_STRING 82 /* 'toString' */
1794#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
1795#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
1796#define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */
1797#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
1798#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
1799#define DUK_STRIDX_TYPE 84 /* 'type' */
1800#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
1801#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
1802#define DUK_STRIDX_DATA 85 /* 'data' */
1803#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
1804#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
1805#define DUK_STRIDX_LC_BUFFER 86 /* 'buffer' */
1806#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
1807#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
1808#define DUK_STRIDX_LENGTH 87 /* 'length' */
1809#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
1810#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
1811#define DUK_STRIDX_SET 88 /* 'set' */
1812#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
1813#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
1814#define DUK_STRIDX_STACK 89 /* 'stack' */
1815#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
1816#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
1817#define DUK_STRIDX_PC 90 /* 'pc' */
1818#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
1819#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
1820#define DUK_STRIDX_LINE_NUMBER 91 /* 'lineNumber' */
1821#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
1822#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
1823#define DUK_STRIDX_INT_TRACEDATA 92 /* '\x82Tracedata' */
1824#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
1825#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
1826#define DUK_STRIDX_NAME 93 /* 'name' */
1827#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
1828#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
1829#define DUK_STRIDX_FILE_NAME 94 /* 'fileName' */
1830#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
1831#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
1832#define DUK_STRIDX_LC_POINTER 95 /* 'pointer' */
1833#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
1834#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
1835#define DUK_STRIDX_INT_TARGET 96 /* '\x82Target' */
1836#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
1837#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
1838#define DUK_STRIDX_INT_NEXT 97 /* '\x82Next' */
1839#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
1840#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
1841#define DUK_STRIDX_INT_BYTECODE 98 /* '\x82Bytecode' */
1842#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
1843#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
1844#define DUK_STRIDX_INT_FORMALS 99 /* '\x82Formals' */
1845#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
1846#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
1847#define DUK_STRIDX_INT_VARMAP 100 /* '\x82Varmap' */
1848#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
1849#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
1850#define DUK_STRIDX_INT_SOURCE 101 /* '\x82Source' */
1851#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
1852#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
1853#define DUK_STRIDX_INT_PC2LINE 102 /* '\x82Pc2line' */
1854#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
1855#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
1856#define DUK_STRIDX_INT_MAP 103 /* '\x82Map' */
1857#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
1858#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
1859#define DUK_STRIDX_INT_VARENV 104 /* '\x82Varenv' */
1860#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
1861#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
1862#define DUK_STRIDX_INT_FINALIZER 105 /* '\x82Finalizer' */
1863#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
1864#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
1865#define DUK_STRIDX_INT_VALUE 106 /* '\x82Value' */
1866#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
1867#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
1868#define DUK_STRIDX_COMPILE 107 /* 'compile' */
1869#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
1870#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
1871#define DUK_STRIDX_INPUT 108 /* 'input' */
1872#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
1873#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
1874#define DUK_STRIDX_ERR_CREATE 109 /* 'errCreate' */
1875#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
1876#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
1877#define DUK_STRIDX_ERR_THROW 110 /* 'errThrow' */
1878#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
1879#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
1880#define DUK_STRIDX_ENV 111 /* 'env' */
1881#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
1882#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
1883#define DUK_STRIDX_HEX 112 /* 'hex' */
1884#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
1885#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
1886#define DUK_STRIDX_BASE64 113 /* 'base64' */
1887#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
1888#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
1889#define DUK_STRIDX_JX 114 /* 'jx' */
1890#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
1891#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
1892#define DUK_STRIDX_JC 115 /* 'jc' */
1893#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
1894#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
1895#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */
1896#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
1897#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
1898#define DUK_STRIDX_JSON_EXT_NAN 117 /* '{"_nan":true}' */
1899#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
1900#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
1901#define DUK_STRIDX_JSON_EXT_POSINF 118 /* '{"_inf":true}' */
1902#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
1903#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
1904#define DUK_STRIDX_JSON_EXT_NEGINF 119 /* '{"_ninf":true}' */
1905#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
1906#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
1907#define DUK_STRIDX_JSON_EXT_FUNCTION1 120 /* '{"_func":true}' */
1908#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
1909#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
1910#define DUK_STRIDX_JSON_EXT_FUNCTION2 121 /* '{_func:true}' */
1911#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
1912#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
1913#define DUK_STRIDX_BREAK 122 /* 'break' */
1914#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
1915#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
1916#define DUK_STRIDX_CASE 123 /* 'case' */
1917#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
1918#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
1919#define DUK_STRIDX_CATCH 124 /* 'catch' */
1920#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
1921#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
1922#define DUK_STRIDX_CONTINUE 125 /* 'continue' */
1923#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
1924#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
1925#define DUK_STRIDX_DEBUGGER 126 /* 'debugger' */
1926#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
1927#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
1928#define DUK_STRIDX_DEFAULT 127 /* 'default' */
1929#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
1930#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
1931#define DUK_STRIDX_DELETE 128 /* 'delete' */
1932#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
1933#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
1934#define DUK_STRIDX_DO 129 /* 'do' */
1935#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
1936#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
1937#define DUK_STRIDX_ELSE 130 /* 'else' */
1938#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
1939#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
1940#define DUK_STRIDX_FINALLY 131 /* 'finally' */
1941#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
1942#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
1943#define DUK_STRIDX_FOR 132 /* 'for' */
1944#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
1945#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
1946#define DUK_STRIDX_LC_FUNCTION 133 /* 'function' */
1947#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
1948#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
1949#define DUK_STRIDX_IF 134 /* 'if' */
1950#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
1951#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
1952#define DUK_STRIDX_IN 135 /* 'in' */
1953#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
1954#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
1955#define DUK_STRIDX_INSTANCEOF 136 /* 'instanceof' */
1956#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
1957#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
1958#define DUK_STRIDX_NEW 137 /* 'new' */
1959#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
1960#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
1961#define DUK_STRIDX_RETURN 138 /* 'return' */
1962#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
1963#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
1964#define DUK_STRIDX_SWITCH 139 /* 'switch' */
1965#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
1966#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
1967#define DUK_STRIDX_THIS 140 /* 'this' */
1968#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
1969#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
1970#define DUK_STRIDX_THROW 141 /* 'throw' */
1971#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
1972#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
1973#define DUK_STRIDX_TRY 142 /* 'try' */
1974#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
1975#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
1976#define DUK_STRIDX_TYPEOF 143 /* 'typeof' */
1977#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
1978#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
1979#define DUK_STRIDX_VAR 144 /* 'var' */
1980#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
1981#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
1982#define DUK_STRIDX_CONST 145 /* 'const' */
1983#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
1984#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
1985#define DUK_STRIDX_VOID 146 /* 'void' */
1986#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
1987#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
1988#define DUK_STRIDX_WHILE 147 /* 'while' */
1989#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
1990#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
1991#define DUK_STRIDX_WITH 148 /* 'with' */
1992#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
1993#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
1994#define DUK_STRIDX_CLASS 149 /* 'class' */
1995#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
1996#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
1997#define DUK_STRIDX_ENUM 150 /* 'enum' */
1998#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
1999#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
2000#define DUK_STRIDX_EXPORT 151 /* 'export' */
2001#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
2002#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
2003#define DUK_STRIDX_EXTENDS 152 /* 'extends' */
2004#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
2005#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
2006#define DUK_STRIDX_IMPORT 153 /* 'import' */
2007#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
2008#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
2009#define DUK_STRIDX_SUPER 154 /* 'super' */
2010#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
2011#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
2012#define DUK_STRIDX_LC_NULL 155 /* 'null' */
2013#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
2014#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
2015#define DUK_STRIDX_TRUE 156 /* 'true' */
2016#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
2017#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
2018#define DUK_STRIDX_FALSE 157 /* 'false' */
2019#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
2020#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
2021#define DUK_STRIDX_IMPLEMENTS 158 /* 'implements' */
2022#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
2023#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
2024#define DUK_STRIDX_INTERFACE 159 /* 'interface' */
2025#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
2026#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
2027#define DUK_STRIDX_LET 160 /* 'let' */
2028#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
2029#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
2030#define DUK_STRIDX_PACKAGE 161 /* 'package' */
2031#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
2032#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
2033#define DUK_STRIDX_PRIVATE 162 /* 'private' */
2034#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
2035#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
2036#define DUK_STRIDX_PROTECTED 163 /* 'protected' */
2037#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
2038#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
2039#define DUK_STRIDX_PUBLIC 164 /* 'public' */
2040#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
2041#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
2042#define DUK_STRIDX_STATIC 165 /* 'static' */
2043#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
2044#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
2045#define DUK_STRIDX_YIELD 166 /* 'yield' */
2046#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
2047#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
2048
2049#define DUK_HEAP_NUM_STRINGS 167
2050#define DUK_STRIDX_START_RESERVED 122
2051#define DUK_STRIDX_START_STRICT_RESERVED 158
2052#define DUK_STRIDX_END_RESERVED 167 /* exclusive endpoint */
2053
2054/* To convert a heap stridx to a token number, subtract
2055 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
2056 */
2057#if !defined(DUK_SINGLE_FILE)
2058DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[972];
2059#endif /* !DUK_SINGLE_FILE */
2060#define DUK_STRDATA_MAX_STRLEN 27
2061#define DUK_STRDATA_DATA_LENGTH 972
2062#endif /* DUK_USE_ROM_STRINGS */
2063
2064#if defined(DUK_USE_ROM_OBJECTS)
2065#error RAM support not enabled, rerun configure.py with --ram-support
2066#else /* DUK_USE_ROM_OBJECTS */
2067DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
2068DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
2069DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
2070DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
2071DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
2072DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
2073DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
2074DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
2075DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
2076DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
2077DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
2078DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
2079DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
2080DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
2081DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
2082DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
2083DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx);
2084DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
2085DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
2086DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
2087DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
2088DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
2089DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
2090DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
2091DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
2092DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
2093DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
2094DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
2095DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
2096DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
2097DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
2098DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
2099DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
2100DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
2101DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
2102DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
2103DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
2104DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
2105DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
2106DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
2107DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
2108DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
2109DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
2110DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
2111DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
2112DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
2113DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
2114DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
2115DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
2116DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
2117DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
2118DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
2119DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
2120DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
2121DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
2122DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
2123DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
2124DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_hasinstance(duk_context *ctx);
2125DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
2126DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
2127DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
2128DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
2129DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
2130DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
2131DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
2132DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
2133DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
2134DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
2135DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
2136DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
2137DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
2138DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
2139DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
2140DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
2141DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
2142DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
2143DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
2144DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
2145DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
2146DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
2147DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
2148DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
2149DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
2150DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
2151DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
2152DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
2153DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
2154DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
2155DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
2156DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
2157DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
2158DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
2159DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx);
2160DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
2161DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
2162DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
2163DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx);
2164DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
2165DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
2166DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
2167DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
2168DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
2169DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
2170DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
2171DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
2172DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
2173DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
2174DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
2175DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
2176DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
2177DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
2178DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
2179DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
2180DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_toprimitive(duk_context *ctx);
2181DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
2182DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
2183DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
2184DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
2185DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
2186DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
2187DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
2188DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
2189DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
2190DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
2191DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
2192DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
2193DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
2194DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
2195DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
2196DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
2197DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
2198DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
2199DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
2200DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
2201DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
2202DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
2203DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
2204DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
2205DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
2206DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
2207DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
2208DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
2209DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
2210DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
2211DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
2212DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
2213DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
2214DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
2215DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
2216DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
2217DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
2218DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
2219DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
2220DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
2221DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx);
2222DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_tostring_shared(duk_context *ctx);
2223DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx);
2224DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
2225DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
2226DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
2227DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
2228DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
2229DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
2230DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
2231DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
2232DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
2233DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
2234DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
2235DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
2236DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
2237DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
2238DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
2239DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
2240DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
2241DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
2242DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
2243DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
2244DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_encode(duk_context *ctx);
2245DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_decode(duk_context *ctx);
2246DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
2247DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
2248DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
2249DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
2250DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
2251#if !defined(DUK_SINGLE_FILE)
2252DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[185];
2253#endif /* !DUK_SINGLE_FILE */
2254#define DUK_BIDX_GLOBAL 0
2255#define DUK_BIDX_GLOBAL_ENV 1
2256#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
2257#define DUK_BIDX_OBJECT_PROTOTYPE 3
2258#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
2259#define DUK_BIDX_FUNCTION_PROTOTYPE 5
2260#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6
2261#define DUK_BIDX_ARRAY_CONSTRUCTOR 7
2262#define DUK_BIDX_ARRAY_PROTOTYPE 8
2263#define DUK_BIDX_STRING_CONSTRUCTOR 9
2264#define DUK_BIDX_STRING_PROTOTYPE 10
2265#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11
2266#define DUK_BIDX_BOOLEAN_PROTOTYPE 12
2267#define DUK_BIDX_NUMBER_CONSTRUCTOR 13
2268#define DUK_BIDX_NUMBER_PROTOTYPE 14
2269#define DUK_BIDX_DATE_CONSTRUCTOR 15
2270#define DUK_BIDX_DATE_PROTOTYPE 16
2271#define DUK_BIDX_REGEXP_CONSTRUCTOR 17
2272#define DUK_BIDX_REGEXP_PROTOTYPE 18
2273#define DUK_BIDX_ERROR_CONSTRUCTOR 19
2274#define DUK_BIDX_ERROR_PROTOTYPE 20
2275#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21
2276#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22
2277#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23
2278#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24
2279#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25
2280#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26
2281#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27
2282#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28
2283#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29
2284#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30
2285#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31
2286#define DUK_BIDX_URI_ERROR_PROTOTYPE 32
2287#define DUK_BIDX_TYPE_ERROR_THROWER 33
2288#define DUK_BIDX_DUKTAPE 34
2289#define DUK_BIDX_THREAD_PROTOTYPE 35
2290#define DUK_BIDX_POINTER_PROTOTYPE 36
2291#define DUK_BIDX_DOUBLE_ERROR 37
2292#define DUK_BIDX_SYMBOL_PROTOTYPE 38
2293#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39
2294#define DUK_BIDX_DATAVIEW_PROTOTYPE 40
2295#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41
2296#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42
2297#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43
2298#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44
2299#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45
2300#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46
2301#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47
2302#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48
2303#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49
2304#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
2305#define DUK_NUM_BUILTINS 51
2306#define DUK_NUM_BIDX_BUILTINS 51
2307#define DUK_NUM_ALL_BUILTINS 80
2308#if defined(DUK_USE_DOUBLE_LE)
2309#if !defined(DUK_SINGLE_FILE)
2310DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
2311#endif /* !DUK_SINGLE_FILE */
2312#define DUK_BUILTINS_DATA_LENGTH 4281
2313#elif defined(DUK_USE_DOUBLE_BE)
2314#if !defined(DUK_SINGLE_FILE)
2315DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
2316#endif /* !DUK_SINGLE_FILE */
2317#define DUK_BUILTINS_DATA_LENGTH 4281
2318#elif defined(DUK_USE_DOUBLE_ME)
2319#if !defined(DUK_SINGLE_FILE)
2320DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
2321#endif /* !DUK_SINGLE_FILE */
2322#define DUK_BUILTINS_DATA_LENGTH 4281
2323#else
2324#error invalid endianness defines
2325#endif
2326#endif /* DUK_USE_ROM_OBJECTS */
2327#endif /* DUK_BUILTINS_H_INCLUDED */
2328#line 45 "duk_internal.h"
2329
2330/* #include duk_util.h */
2331#line 1 "duk_util.h"
2332/*
2333 * Utilities
2334 */
2335
2336#if !defined(DUK_UTIL_H_INCLUDED)
2337#define DUK_UTIL_H_INCLUDED
2338
2339#if defined(DUK_USE_GET_RANDOM_DOUBLE)
2340#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata)
2341#else
2342#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr)
2343#endif
2344
2345/*
2346 * Some useful constants
2347 */
2348
2349#define DUK_DOUBLE_2TO32 4294967296.0
2350#define DUK_DOUBLE_2TO31 2147483648.0
2351#define DUK_DOUBLE_LOG2E 1.4426950408889634
2352#define DUK_DOUBLE_LOG10E 0.4342944819032518
2353
2354/*
2355 * Endian conversion
2356 */
2357
2358#if defined(DUK_USE_INTEGER_LE)
2359#define DUK_HTON32(x) DUK_BSWAP32((x))
2360#define DUK_NTOH32(x) DUK_BSWAP32((x))
2361#define DUK_HTON16(x) DUK_BSWAP16((x))
2362#define DUK_NTOH16(x) DUK_BSWAP16((x))
2363#elif defined(DUK_USE_INTEGER_BE)
2364#define DUK_HTON32(x) (x)
2365#define DUK_NTOH32(x) (x)
2366#define DUK_HTON16(x) (x)
2367#define DUK_NTOH16(x) (x)
2368#else
2369#error internal error, endianness defines broken
2370#endif
2371
2372/*
2373 * Bitstream decoder
2374 */
2375
2376struct duk_bitdecoder_ctx {
2377 const duk_uint8_t *data;
2378 duk_size_t offset;
2379 duk_size_t length;
2380 duk_uint32_t currval;
2381 duk_small_int_t currbits;
2382};
2383
2384#define DUK_BD_BITPACKED_STRING_MAXLEN 256
2385
2386/*
2387 * Bitstream encoder
2388 */
2389
2390struct duk_bitencoder_ctx {
2391 duk_uint8_t *data;
2392 duk_size_t offset;
2393 duk_size_t length;
2394 duk_uint32_t currval;
2395 duk_small_int_t currbits;
2396 duk_small_int_t truncated;
2397};
2398
2399/*
2400 * Raw write/read macros for big endian, unaligned basic values.
2401 * Caller ensures there's enough space. The INC macro variants
2402 * update the pointer argument automatically.
2403 */
2404
2405#define DUK_RAW_WRITE_U8(ptr,val) do { \
2406 *(ptr) = (duk_uint8_t) (val); \
2407 } while (0)
2408#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be((ptr), (duk_uint16_t) (val))
2409#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be((ptr), (duk_uint32_t) (val))
2410#define DUK_RAW_WRITE_FLOAT_BE(ptr,val) duk_raw_write_float_be((ptr), (duk_float_t) (val))
2411#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be((ptr), (duk_double_t) (val))
2412#define DUK_RAW_WRITE_XUTF8(ptr,val) duk_raw_write_xutf8((ptr), (duk_ucodepoint_t) (val))
2413
2414#define DUK_RAW_WRITEINC_U8(ptr,val) do { \
2415 *(ptr)++ = (duk_uint8_t) (val); \
2416 } while (0)
2417#define DUK_RAW_WRITEINC_U16_BE(ptr,val) duk_raw_writeinc_u16_be(&(ptr), (duk_uint16_t) (val))
2418#define DUK_RAW_WRITEINC_U32_BE(ptr,val) duk_raw_writeinc_u32_be(&(ptr), (duk_uint32_t) (val))
2419#define DUK_RAW_WRITEINC_FLOAT_BE(ptr,val) duk_raw_writeinc_float_be(&(ptr), (duk_float_t) (val))
2420#define DUK_RAW_WRITEINC_DOUBLE_BE(ptr,val) duk_raw_writeinc_double_be(&(ptr), (duk_double_t) (val))
2421#define DUK_RAW_WRITEINC_XUTF8(ptr,val) duk_raw_writeinc_xutf8(&(ptr), (duk_ucodepoint_t) (val))
2422#define DUK_RAW_WRITEINC_CESU8(ptr,val) duk_raw_writeinc_cesu8(&(ptr), (duk_ucodepoint_t) (val))
2423
2424#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)))
2425#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be((ptr));
2426#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be((ptr));
2427#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be((ptr));
2428
2429#define DUK_RAW_READINC_U8(ptr) ((duk_uint8_t) (*(ptr)++))
2430#define DUK_RAW_READINC_U16_BE(ptr) duk_raw_readinc_u16_be(&(ptr));
2431#define DUK_RAW_READINC_U32_BE(ptr) duk_raw_readinc_u32_be(&(ptr));
2432#define DUK_RAW_READINC_DOUBLE_BE(ptr) duk_raw_readinc_double_be(&(ptr));
2433
2434/*
2435 * Double and float byte order operations.
2436 */
2437
2438DUK_INTERNAL_DECL void duk_dblunion_host_to_little(duk_double_union *u);
2439DUK_INTERNAL_DECL void duk_dblunion_little_to_host(duk_double_union *u);
2440DUK_INTERNAL_DECL void duk_dblunion_host_to_big(duk_double_union *u);
2441DUK_INTERNAL_DECL void duk_dblunion_big_to_host(duk_double_union *u);
2442DUK_INTERNAL_DECL void duk_fltunion_host_to_big(duk_float_union *u);
2443DUK_INTERNAL_DECL void duk_fltunion_big_to_host(duk_float_union *u);
2444
2445/*
2446 * Buffer writer (dynamic buffer only)
2447 *
2448 * Helper for writing to a dynamic buffer with a concept of a "slack" area
2449 * to reduce resizes. You can ensure there is enough space beforehand and
2450 * then write for a while without further checks, relying on a stable data
2451 * pointer. Slack handling is automatic so call sites only indicate how
2452 * much data they need right now.
2453 *
2454 * There are several ways to write using bufwriter. The best approach
2455 * depends mainly on how much performance matters over code footprint.
2456 * The key issues are (1) ensuring there is space and (2) keeping the
2457 * pointers consistent. Fast code should ensure space for multiple writes
2458 * with one ensure call. Fastest inner loop code can temporarily borrow
2459 * the 'p' pointer but must write it back eventually.
2460 *
2461 * Be careful to ensure all macro arguments (other than static pointers like
2462 * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
2463 * necessary (if that's not possible, there should be a note near the macro).
2464 * Buffer write arguments often contain arithmetic etc so this is
2465 * particularly important here.
2466 */
2467
2468/* XXX: Migrate bufwriter and other read/write helpers to its own header? */
2469
2470struct duk_bufwriter_ctx {
2471 duk_uint8_t *p;
2472 duk_uint8_t *p_base;
2473 duk_uint8_t *p_limit;
2474 duk_hbuffer_dynamic *buf;
2475};
2476
2477#if defined(DUK_USE_PREFER_SIZE)
2478#define DUK_BW_SLACK_ADD 64
2479#define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */
2480#else
2481#define DUK_BW_SLACK_ADD 64
2482#define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */
2483#endif
2484
2485/* Initialization and finalization (compaction), converting to other types. */
2486
2487#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
2488 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
2489 } while (0)
2490#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
2491 duk_bw_init((thr), (bw_ctx), (buf)); \
2492 } while (0)
2493#define DUK_BW_COMPACT(thr,bw_ctx) do { \
2494 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
2495 duk_bw_compact((thr), (bw_ctx)); \
2496 } while (0)
2497#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
2498 duk_push_lstring((thr), \
2499 (const char *) (bw_ctx)->p_base, \
2500 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
2501 } while (0)
2502
2503/* Pointers may be NULL for a while when 'buf' size is zero and before any
2504 * ENSURE calls have been made. Once an ENSURE has been made, the pointers
2505 * are required to be non-NULL so that it's always valid to use memcpy() and
2506 * memmove(), even for zero size.
2507 */
2508#if defined(DUK_USE_ASSERTIONS)
2509DUK_INTERNAL_DECL void duk_bw_assert_valid(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2510#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) (duk_bw_assert_valid((thr), (bw_ctx)))
2511#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { duk_bw_assert_valid((thr), (bw_ctx)); } while (0)
2512#else
2513#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) DUK_ASSERT_EXPR(1)
2514#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do {} while (0)
2515#endif
2516
2517/* Working with the pointer and current size. */
2518
2519#define DUK_BW_GET_PTR(thr,bw_ctx) \
2520 ((bw_ctx)->p)
2521#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
2522 (bw_ctx)->p = (ptr); \
2523 } while (0)
2524#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
2525 (bw_ctx)->p += (delta); \
2526 } while (0)
2527#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
2528 ((bw_ctx)->p_base)
2529#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
2530 ((bw_ctx)->p_limit)
2531#define DUK_BW_GET_SIZE(thr,bw_ctx) \
2532 ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
2533#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
2534 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
2535 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
2536 } while (0)
2537#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
2538 /* Reset to zero size, keep current limit. */ \
2539 (bw_ctx)->p = (bw_ctx)->p_base; \
2540 } while (0)
2541#define DUK_BW_GET_BUFFER(thr,bw_ctx) \
2542 ((bw_ctx)->buf)
2543
2544/* Ensuring (reserving) space. */
2545
2546#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
2547 duk_size_t duk__sz, duk__space; \
2548 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
2549 duk__sz = (sz); \
2550 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
2551 if (duk__space < duk__sz) { \
2552 (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
2553 } \
2554 } while (0)
2555/* NOTE: Multiple evaluation of 'ptr' in this macro. */
2556/* XXX: Rework to use an always-inline function? */
2557#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
2558 (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
2559 (ptr) : \
2560 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
2561#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
2562 DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
2563#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
2564 (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
2565 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
2566#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
2567 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
2568 } while (0)
2569
2570/* Miscellaneous. */
2571
2572#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
2573 (bw_ctx)->p = (ptr); \
2574 duk_bw_compact((thr), (bw_ctx)); \
2575 } while (0)
2576
2577/* Fast write calls which assume you control the slack beforehand.
2578 * Multibyte write variants exist and use a temporary write pointer
2579 * because byte writes alias with anything: with a stored pointer
2580 * explicit pointer load/stores get generated (e.g. gcc -Os).
2581 */
2582
2583#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
2584 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
2585 *(bw_ctx)->p++ = (duk_uint8_t) (val); \
2586 } while (0)
2587#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
2588 duk_uint8_t *duk__p; \
2589 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
2590 duk__p = (bw_ctx)->p; \
2591 *duk__p++ = (duk_uint8_t) (val1); \
2592 *duk__p++ = (duk_uint8_t) (val2); \
2593 (bw_ctx)->p = duk__p; \
2594 } while (0)
2595#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2596 duk_uint8_t *duk__p; \
2597 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
2598 duk__p = (bw_ctx)->p; \
2599 *duk__p++ = (duk_uint8_t) (val1); \
2600 *duk__p++ = (duk_uint8_t) (val2); \
2601 *duk__p++ = (duk_uint8_t) (val3); \
2602 (bw_ctx)->p = duk__p; \
2603 } while (0)
2604#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2605 duk_uint8_t *duk__p; \
2606 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
2607 duk__p = (bw_ctx)->p; \
2608 *duk__p++ = (duk_uint8_t) (val1); \
2609 *duk__p++ = (duk_uint8_t) (val2); \
2610 *duk__p++ = (duk_uint8_t) (val3); \
2611 *duk__p++ = (duk_uint8_t) (val4); \
2612 (bw_ctx)->p = duk__p; \
2613 } while (0)
2614#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2615 duk_uint8_t *duk__p; \
2616 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
2617 duk__p = (bw_ctx)->p; \
2618 *duk__p++ = (duk_uint8_t) (val1); \
2619 *duk__p++ = (duk_uint8_t) (val2); \
2620 *duk__p++ = (duk_uint8_t) (val3); \
2621 *duk__p++ = (duk_uint8_t) (val4); \
2622 *duk__p++ = (duk_uint8_t) (val5); \
2623 (bw_ctx)->p = duk__p; \
2624 } while (0)
2625#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2626 duk_uint8_t *duk__p; \
2627 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
2628 duk__p = (bw_ctx)->p; \
2629 *duk__p++ = (duk_uint8_t) (val1); \
2630 *duk__p++ = (duk_uint8_t) (val2); \
2631 *duk__p++ = (duk_uint8_t) (val3); \
2632 *duk__p++ = (duk_uint8_t) (val4); \
2633 *duk__p++ = (duk_uint8_t) (val5); \
2634 *duk__p++ = (duk_uint8_t) (val6); \
2635 (bw_ctx)->p = duk__p; \
2636 } while (0)
2637#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
2638 duk_ucodepoint_t duk__cp; \
2639 duk_small_int_t duk__enc_len; \
2640 duk__cp = (duk_ucodepoint_t) (cp); \
2641 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
2642 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
2643 (bw_ctx)->p += duk__enc_len; \
2644 } while (0)
2645#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
2646 duk_ucodepoint_t duk__cp; \
2647 duk_small_int_t duk__enc_len; \
2648 duk__cp = (duk_ucodepoint_t) (cp); \
2649 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
2650 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
2651 (bw_ctx)->p += duk__enc_len; \
2652 } while (0)
2653/* XXX: add temporary duk__p pointer here too; sharing */
2654/* XXX: avoid unsafe variants */
2655#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
2656 const void *duk__valptr; \
2657 duk_size_t duk__valsz; \
2658 duk__valptr = (const void *) (valptr); \
2659 duk__valsz = (duk_size_t) (valsz); \
2660 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2661 (bw_ctx)->p += duk__valsz; \
2662 } while (0)
2663#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
2664 const duk_uint8_t *duk__val; \
2665 duk_size_t duk__val_len; \
2666 duk__val = (const duk_uint8_t *) (val); \
2667 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2668 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2669 (bw_ctx)->p += duk__val_len; \
2670 } while (0)
2671#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
2672 duk_size_t duk__val_len; \
2673 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2674 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2675 (bw_ctx)->p += duk__val_len; \
2676 } while (0)
2677#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
2678 duk_size_t duk__val_len; \
2679 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2680 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2681 (bw_ctx)->p += duk__val_len; \
2682 } while (0)
2683#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2684 duk_size_t duk__val_len; \
2685 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2686 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2687 (bw_ctx)->p += duk__val_len; \
2688 } while (0)
2689#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2690 duk_size_t duk__val_len; \
2691 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2692 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2693 (bw_ctx)->p += duk__val_len; \
2694 } while (0)
2695
2696/* Append bytes from a slice already in the buffer. */
2697#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
2698 duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
2699
2700/* Insert bytes in the middle of the buffer from an external buffer. */
2701#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
2702 duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
2703
2704/* Insert bytes in the middle of the buffer from a slice already
2705 * in the buffer. Source offset is interpreted "before" the operation.
2706 */
2707#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
2708 duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
2709
2710/* Insert a reserved area somewhere in the buffer; caller fills it.
2711 * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
2712 * area for convenience.
2713 */
2714#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
2715 duk_bw_insert_raw_area((thr), (bw), (off), (len))
2716
2717/* Remove a slice from inside buffer. */
2718#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
2719 duk_bw_remove_raw_slice((thr), (bw), (off), (len))
2720
2721/* Safe write calls which will ensure space first. */
2722
2723#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
2724 DUK_BW_ENSURE((thr), (bw_ctx), 1); \
2725 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
2726 } while (0)
2727#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
2728 DUK_BW_ENSURE((thr), (bw_ctx), 2); \
2729 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
2730 } while (0)
2731#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2732 DUK_BW_ENSURE((thr), (bw_ctx), 3); \
2733 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
2734 } while (0)
2735#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2736 DUK_BW_ENSURE((thr), (bw_ctx), 4); \
2737 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
2738 } while (0)
2739#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2740 DUK_BW_ENSURE((thr), (bw_ctx), 5); \
2741 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
2742 } while (0)
2743#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2744 DUK_BW_ENSURE((thr), (bw_ctx), 6); \
2745 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
2746 } while (0)
2747#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
2748 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
2749 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
2750 } while (0)
2751#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
2752 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
2753 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
2754 } while (0)
2755/* XXX: add temporary duk__p pointer here too; sharing */
2756/* XXX: avoid unsafe */
2757#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
2758 const void *duk__valptr; \
2759 duk_size_t duk__valsz; \
2760 duk__valptr = (const void *) (valptr); \
2761 duk__valsz = (duk_size_t) (valsz); \
2762 DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
2763 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2764 (bw_ctx)->p += duk__valsz; \
2765 } while (0)
2766#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
2767 const duk_uint8_t *duk__val; \
2768 duk_size_t duk__val_len; \
2769 duk__val = (const duk_uint8_t *) (val); \
2770 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2771 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2772 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2773 (bw_ctx)->p += duk__val_len; \
2774 } while (0)
2775#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
2776 duk_size_t duk__val_len; \
2777 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2778 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2779 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2780 (bw_ctx)->p += duk__val_len; \
2781 } while (0)
2782#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
2783 duk_size_t duk__val_len; \
2784 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2785 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2786 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2787 (bw_ctx)->p += duk__val_len; \
2788 } while (0)
2789#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2790 duk_size_t duk__val_len; \
2791 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2792 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2793 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2794 (bw_ctx)->p += duk__val_len; \
2795 } while (0)
2796#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2797 duk_size_t duk__val_len; \
2798 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2799 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2800 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2801 (bw_ctx)->p += duk__val_len; \
2802 } while (0)
2803
2804#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
2805 duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
2806#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
2807 duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
2808#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
2809 duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
2810#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
2811 /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
2812 duk_bw_insert_ensure_area((thr), (bw), (off), (len))
2813#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
2814 /* No difference between raw/ensure because the buffer shrinks. */ \
2815 DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
2816
2817/*
2818 * Externs and prototypes
2819 */
2820
2821#if !defined(DUK_SINGLE_FILE)
2822DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
2823DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
2824DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
2825#if defined(DUK_USE_HEX_FASTPATH)
2826DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
2827DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
2828#endif
2829#endif /* !DUK_SINGLE_FILE */
2830
2831/* Note: assumes that duk_util_probe_steps size is 32 */
2832#if defined(DUK_USE_HOBJECT_HASH_PART)
2833#if !defined(DUK_SINGLE_FILE)
2834DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
2835#endif /* !DUK_SINGLE_FILE */
2836#endif
2837
2838#if defined(DUK_USE_STRHASH_DENSE)
2839DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
2840#endif
2841
2842DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
2843DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
2844DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value);
2845DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
2846DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx);
2847DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out);
2848
2849DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
2850DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
2851
2852#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
2853DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
2854DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr);
2855#endif
2856
2857DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
2858DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
2859DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
2860DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2861DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2862DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2863DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
2864DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
2865DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
2866DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
2867DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2868DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2869DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2870/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
2871
2872DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(const duk_uint8_t *p);
2873DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(const duk_uint8_t *p);
2874DUK_INTERNAL_DECL duk_float_t duk_raw_read_float_be(const duk_uint8_t *p);
2875DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(const duk_uint8_t *p);
2876DUK_INTERNAL_DECL duk_uint16_t duk_raw_readinc_u16_be(const duk_uint8_t **p);
2877DUK_INTERNAL_DECL duk_uint32_t duk_raw_readinc_u32_be(const duk_uint8_t **p);
2878DUK_INTERNAL_DECL duk_float_t duk_raw_readinc_float_be(const duk_uint8_t **p);
2879DUK_INTERNAL_DECL duk_double_t duk_raw_readinc_double_be(const duk_uint8_t **p);
2880DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t *p, duk_uint16_t val);
2881DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t *p, duk_uint32_t val);
2882DUK_INTERNAL_DECL void duk_raw_write_float_be(duk_uint8_t *p, duk_float_t val);
2883DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t *p, duk_double_t val);
2884DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_xutf8(duk_uint8_t *p, duk_ucodepoint_t val);
2885DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_cesu8(duk_uint8_t *p, duk_ucodepoint_t val);
2886DUK_INTERNAL_DECL void duk_raw_writeinc_u16_be(duk_uint8_t **p, duk_uint16_t val);
2887DUK_INTERNAL_DECL void duk_raw_writeinc_u32_be(duk_uint8_t **p, duk_uint32_t val);
2888DUK_INTERNAL_DECL void duk_raw_writeinc_float_be(duk_uint8_t **p, duk_float_t val);
2889DUK_INTERNAL_DECL void duk_raw_writeinc_double_be(duk_uint8_t **p, duk_double_t val);
2890DUK_INTERNAL_DECL void duk_raw_writeinc_xutf8(duk_uint8_t **p, duk_ucodepoint_t val);
2891DUK_INTERNAL_DECL void duk_raw_writeinc_cesu8(duk_uint8_t **p, duk_ucodepoint_t val);
2892
2893#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
2894DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
2895#endif
2896
2897/* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy()
2898 * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the
2899 * operation size is zero. The unsafe variants like duk_memcpy_safe() deal
2900 * with the zero size case explicitly, and allow NULL pointers in that case
2901 * (which is undefined behavior in C99+). For the majority of actual targets
2902 * a NULL pointer with a zero length is fine in practice. These wrappers are
2903 * macros to force inlining; because there are hundreds of call sites, even a
2904 * few extra bytes per call site adds up to ~1kB footprint.
2905 */
2906#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
2907#define duk_memcpy(dst,src,len) do { \
2908 void *duk__dst = (dst); \
2909 const void *duk__src = (src); \
2910 duk_size_t duk__len = (len); \
2911 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2912 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2913 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2914 } while (0)
2915#define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len))
2916#define duk_memmove(dst,src,len) do { \
2917 void *duk__dst = (dst); \
2918 const void *duk__src = (src); \
2919 duk_size_t duk__len = (len); \
2920 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2921 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2922 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2923 } while (0)
2924#define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len))
2925#define duk_memset(dst,val,len) do { \
2926 void *duk__dst = (dst); \
2927 duk_small_int_t duk__val = (val); \
2928 duk_size_t duk__len = (len); \
2929 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2930 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2931 } while (0)
2932#define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len))
2933#define duk_memzero(dst,len) do { \
2934 void *duk__dst = (dst); \
2935 duk_size_t duk__len = (len); \
2936 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2937 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
2938 } while (0)
2939#define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len))
2940#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
2941#define duk_memcpy(dst,src,len) do { \
2942 void *duk__dst = (dst); \
2943 const void *duk__src = (src); \
2944 duk_size_t duk__len = (len); \
2945 DUK_ASSERT(duk__dst != NULL); \
2946 DUK_ASSERT(duk__src != NULL); \
2947 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2948 } while (0)
2949#define duk_memcpy_unsafe(dst,src,len) do { \
2950 void *duk__dst = (dst); \
2951 const void *duk__src = (src); \
2952 duk_size_t duk__len = (len); \
2953 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2954 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2955 if (DUK_LIKELY(duk__len > 0U)) { \
2956 DUK_ASSERT(duk__dst != NULL); \
2957 DUK_ASSERT(duk__src != NULL); \
2958 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2959 } \
2960 } while (0)
2961#define duk_memmove(dst,src,len) do { \
2962 void *duk__dst = (dst); \
2963 const void *duk__src = (src); \
2964 duk_size_t duk__len = (len); \
2965 DUK_ASSERT(duk__dst != NULL); \
2966 DUK_ASSERT(duk__src != NULL); \
2967 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2968 } while (0)
2969#define duk_memmove_unsafe(dst,src,len) do { \
2970 void *duk__dst = (dst); \
2971 const void *duk__src = (src); \
2972 duk_size_t duk__len = (len); \
2973 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2974 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2975 if (DUK_LIKELY(duk__len > 0U)) { \
2976 DUK_ASSERT(duk__dst != NULL); \
2977 DUK_ASSERT(duk__src != NULL); \
2978 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2979 } \
2980 } while (0)
2981#define duk_memset(dst,val,len) do { \
2982 void *duk__dst = (dst); \
2983 duk_small_int_t duk__val = (val); \
2984 duk_size_t duk__len = (len); \
2985 DUK_ASSERT(duk__dst != NULL); \
2986 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2987 } while (0)
2988#define duk_memset_unsafe(dst,val,len) do { \
2989 void *duk__dst = (dst); \
2990 duk_small_int_t duk__val = (val); \
2991 duk_size_t duk__len = (len); \
2992 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2993 if (DUK_LIKELY(duk__len > 0U)) { \
2994 DUK_ASSERT(duk__dst != NULL); \
2995 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2996 } \
2997 } while (0)
2998#define duk_memzero(dst,len) do { \
2999 void *duk__dst = (dst); \
3000 duk_size_t duk__len = (len); \
3001 DUK_ASSERT(duk__dst != NULL); \
3002 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
3003 } while (0)
3004#define duk_memzero_unsafe(dst,len) do { \
3005 void *duk__dst = (dst); \
3006 duk_size_t duk__len = (len); \
3007 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
3008 if (DUK_LIKELY(duk__len > 0U)) { \
3009 DUK_ASSERT(duk__dst != NULL); \
3010 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
3011 } \
3012 } while (0)
3013#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
3014
3015DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len);
3016DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len);
3017
3018DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
3019DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
3020DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
3021DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x);
3022DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x);
3023DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x);
3024DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x);
3025DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x);
3026DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x);
3027DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x);
3028DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
3029DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
3030DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
3031DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
3032DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x);
3033DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x);
3034DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x);
3035
3036DUK_INTERNAL_DECL duk_double_t duk_double_div(duk_double_t x, duk_double_t y);
3037DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x);
3038DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x);
3039DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x);
3040DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x);
3041DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x);
3042DUK_INTERNAL_DECL duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y);
3043DUK_INTERNAL_DECL duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y);
3044
3045/*
3046 * Miscellaneous
3047 */
3048
3049/* Example: x = 0x10 = 0b00010000
3050 * x - 1 = 0x0f = 0b00001111
3051 * x & (x - 1) == 0
3052 *
3053 * x = 0x07 = 0b00000111
3054 * x - 1 = 0x06 = 0b00000110
3055 * x & (x - 1) != 0
3056 *
3057 * However, incorrectly true for x == 0 so check for that explicitly.
3058 */
3059#define DUK_IS_POWER_OF_TWO(x) \
3060 ((x) != 0U && ((x) & ((x) - 1U)) == 0U)
3061
3062#endif /* DUK_UTIL_H_INCLUDED */
3063/* #include duk_strings.h */
3064#line 1 "duk_strings.h"
3065/*
3066 * Shared string macros.
3067 *
3068 * Using shared macros helps minimize strings data size because it's easy
3069 * to check if an existing string could be used. String constants don't
3070 * need to be all defined here; defining a string here makes sense if there's
3071 * a high chance the string could be reused. Also, using macros allows
3072 * a call site express the exact string needed, but the macro may map to an
3073 * approximate string to reduce unique string count. Macros can also be
3074 * more easily tuned for low memory targets than #if defined()s throughout
3075 * the code base.
3076 *
3077 * Because format strings behave differently in the call site (they need to
3078 * be followed by format arguments), they use a special prefix DUK_STR_FMT_.
3079 *
3080 * On some compilers using explicit shared strings is preferable; on others
3081 * it may be better to use straight literals because the compiler will combine
3082 * them anyway, and such strings won't end up unnecessarily in a symbol table.
3083 */
3084
3085#if !defined(DUK_ERRMSG_H_INCLUDED)
3086#define DUK_ERRMSG_H_INCLUDED
3087
3088/* Mostly API and built-in method related */
3089#define DUK_STR_INTERNAL_ERROR "internal error"
3090#define DUK_STR_UNSUPPORTED "unsupported"
3091#define DUK_STR_INVALID_COUNT "invalid count"
3092#define DUK_STR_INVALID_ARGS "invalid args"
3093#define DUK_STR_INVALID_STATE "invalid state"
3094#define DUK_STR_INVALID_INPUT "invalid input"
3095#define DUK_STR_INVALID_LENGTH "invalid length"
3096#define DUK_STR_NOT_CONSTRUCTABLE "not constructable"
3097#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'"
3098#define DUK_STR_NOT_CALLABLE "not callable"
3099#define DUK_STR_NOT_EXTENSIBLE "not extensible"
3100#define DUK_STR_NOT_WRITABLE "not writable"
3101#define DUK_STR_NOT_CONFIGURABLE "not configurable"
3102#define DUK_STR_INVALID_CONTEXT "invalid context"
3103#define DUK_STR_INVALID_INDEX "invalid args"
3104#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack"
3105#define DUK_STR_NOT_UNDEFINED "unexpected type"
3106#define DUK_STR_NOT_NULL "unexpected type"
3107#define DUK_STR_NOT_BOOLEAN "unexpected type"
3108#define DUK_STR_NOT_NUMBER "unexpected type"
3109#define DUK_STR_NOT_STRING "unexpected type"
3110#define DUK_STR_NOT_OBJECT "unexpected type"
3111#define DUK_STR_NOT_POINTER "unexpected type"
3112#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */
3113#define DUK_STR_UNEXPECTED_TYPE "unexpected type"
3114#define DUK_STR_NOT_THREAD "unexpected type"
3115#define DUK_STR_NOT_COMPFUNC "unexpected type"
3116#define DUK_STR_NOT_NATFUNC "unexpected type"
3117#define DUK_STR_NOT_C_FUNCTION "unexpected type"
3118#define DUK_STR_NOT_FUNCTION "unexpected type"
3119#define DUK_STR_NOT_REGEXP "unexpected type"
3120#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed"
3121#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range"
3122#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible"
3123#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol"
3124#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol"
3125#define DUK_STR_STRING_TOO_LONG "string too long"
3126#define DUK_STR_BUFFER_TOO_LONG "buffer too long"
3127#define DUK_STR_ALLOC_FAILED "alloc failed"
3128#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type"
3129#define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed"
3130#define DUK_STR_SOURCE_DECODE_FAILED "source decode failed"
3131#define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed"
3132#define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed"
3133#define DUK_STR_HEX_DECODE_FAILED "hex decode failed"
3134#define DUK_STR_INVALID_BYTECODE "invalid bytecode"
3135#define DUK_STR_NO_SOURCECODE "no sourcecode"
3136#define DUK_STR_RESULT_TOO_LONG "result too long"
3137#define DUK_STR_INVALID_CFUNC_RC "invalid C function rc"
3138#define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval"
3139#define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype"
3140
3141/* JSON */
3142#define DUK_STR_FMT_PTR "%p"
3143#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)"
3144#define DUK_STR_CYCLIC_INPUT "cyclic input"
3145
3146/* Generic codec */
3147#define DUK_STR_DEC_RECLIMIT "decode recursion limit"
3148#define DUK_STR_ENC_RECLIMIT "encode recursion limit"
3149
3150/* Object property access */
3151#define DUK_STR_INVALID_BASE "invalid base value"
3152#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'"
3153#define DUK_STR_PROXY_REJECTED "proxy rejected"
3154#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length"
3155#define DUK_STR_SETTER_UNDEFINED "setter undefined"
3156#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor"
3157
3158/* Proxy */
3159#define DUK_STR_PROXY_REVOKED "proxy revoked"
3160#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result"
3161
3162/* Variables */
3163
3164/* Lexer */
3165#define DUK_STR_INVALID_ESCAPE "invalid escape"
3166#define DUK_STR_UNTERMINATED_STRING "unterminated string"
3167#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment"
3168#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp"
3169#define DUK_STR_TOKEN_LIMIT "token limit"
3170#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled"
3171#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal"
3172#define DUK_STR_INVALID_TOKEN "invalid token"
3173
3174/* Compiler */
3175#define DUK_STR_PARSE_ERROR "parse error"
3176#define DUK_STR_DUPLICATE_LABEL "duplicate label"
3177#define DUK_STR_INVALID_LABEL "invalid label"
3178#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal"
3179#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal"
3180#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration"
3181#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier"
3182#define DUK_STR_INVALID_EXPRESSION "invalid expression"
3183#define DUK_STR_INVALID_LVALUE "invalid lvalue"
3184#define DUK_STR_INVALID_NEWTARGET "invalid new.target"
3185#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier"
3186#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed"
3187#define DUK_STR_INVALID_FOR "invalid for statement"
3188#define DUK_STR_INVALID_SWITCH "invalid switch statement"
3189#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label"
3190#define DUK_STR_INVALID_RETURN "invalid return"
3191#define DUK_STR_INVALID_TRY "invalid try"
3192#define DUK_STR_INVALID_THROW "invalid throw"
3193#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode"
3194#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed"
3195#define DUK_STR_UNTERMINATED_STMT "unterminated statement"
3196#define DUK_STR_INVALID_ARG_NAME "invalid argument name"
3197#define DUK_STR_INVALID_FUNC_NAME "invalid function name"
3198#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name"
3199#define DUK_STR_FUNC_NAME_REQUIRED "function name required"
3200
3201/* RegExp */
3202#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier"
3203#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom"
3204#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)"
3205#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies"
3206#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis"
3207#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern"
3208#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp"
3209#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags"
3210#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape"
3211#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)"
3212#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character"
3213#define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group"
3214#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class"
3215#define DUK_STR_INVALID_RANGE "invalid range"
3216
3217/* Limits */
3218#define DUK_STR_VALSTACK_LIMIT "valstack limit"
3219#define DUK_STR_CALLSTACK_LIMIT "callstack limit"
3220#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit"
3221#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit"
3222#define DUK_STR_NATIVE_STACK_LIMIT "C stack depth limit"
3223#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit"
3224#define DUK_STR_BYTECODE_LIMIT "bytecode limit"
3225#define DUK_STR_REG_LIMIT "register limit"
3226#define DUK_STR_TEMP_LIMIT "temp limit"
3227#define DUK_STR_CONST_LIMIT "const limit"
3228#define DUK_STR_FUNC_LIMIT "function limit"
3229#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit"
3230#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit"
3231#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit"
3232
3233#endif /* DUK_ERRMSG_H_INCLUDED */
3234/* #include duk_js_bytecode.h */
3235#line 1 "duk_js_bytecode.h"
3236/*
3237 * ECMAScript bytecode
3238 */
3239
3240#if !defined(DUK_JS_BYTECODE_H_INCLUDED)
3241#define DUK_JS_BYTECODE_H_INCLUDED
3242
3243/*
3244 * Bytecode instruction layout
3245 * ===========================
3246 *
3247 * Instructions are unsigned 32-bit integers divided as follows:
3248 *
3249 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3250 * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
3251 * +-----------------------------------------------+---------------+
3252 * ! C ! B ! A ! OP !
3253 * +-----------------------------------------------+---------------+
3254 *
3255 * OP (8 bits): opcode (DUK_OP_*), access should be fastest
3256 * consecutive opcodes allocated when opcode needs flags
3257 * A (8 bits): typically a target register number
3258 * B (8 bits): typically first source register/constant number
3259 * C (8 bits): typically second source register/constant number
3260 *
3261 * Some instructions combine BC or ABC together for larger parameter values.
3262 * Signed integers (e.g. jump offsets) are encoded as unsigned, with an
3263 * opcode specific bias.
3264 *
3265 * Some opcodes have flags which are handled by allocating consecutive
3266 * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A'
3267 * field when there's room for the specific opcode.
3268 *
3269 * For example, if three flags were needed, they could be allocated from
3270 * the opcode field as follows:
3271 *
3272 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3273 * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
3274 * +-----------------------------------------------+---------------+
3275 * ! C ! B ! A ! OP !Z!Y!X!
3276 * +-----------------------------------------------+---------------+
3277 *
3278 * Some opcodes accept a reg/const argument which is handled by allocating
3279 * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The
3280 * following convention is shared by most opcodes, so that the compiler
3281 * can handle reg/const flagging without opcode specific code paths:
3282 *
3283 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3284 * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
3285 * +-----------------------------------------------+---------------+
3286 * ! C ! B ! A ! OP !Y!X!
3287 * +-----------------------------------------------+---------------+
3288 *
3289 * X 1=B is const, 0=B is reg
3290 * Y 1=C is const, 0=C is reg
3291 *
3292 * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the
3293 * 8-bit opcode space for a single logical opcode. The base opcode
3294 * number should be divisible by 4. If the opcode is called 'FOO'
3295 * the following opcode constants would be defined:
3296 *
3297 * DUK_OP_FOO 100 // base opcode number
3298 * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg
3299 * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg
3300 * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const
3301 * DUK_OP_FOO_CC 103 // FOO, B=const, C=const
3302 *
3303 * If only B or C is a reg/const, the unused opcode combinations can be
3304 * used for other opcodes (which take no reg/const argument). However,
3305 * such opcode values are initially reserved, at least while opcode space
3306 * is available. For example, if 'BAR' uses B for a register field and
3307 * C is a reg/const:
3308 *
3309 * DUK_OP_BAR 116 // base opcode number
3310 * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg
3311 * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed
3312 * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const
3313 * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed
3314 *
3315 * Macro naming is a bit misleading, e.g. "ABC" in macro name but the
3316 * field layout is concretely "CBA" in the register.
3317 */
3318
3319typedef duk_uint32_t duk_instr_t;
3320
3321#define DUK_BC_SHIFT_OP 0
3322#define DUK_BC_SHIFT_A 8
3323#define DUK_BC_SHIFT_B 16
3324#define DUK_BC_SHIFT_C 24
3325#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B
3326#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A
3327
3328#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL
3329#define DUK_BC_UNSHIFTED_MASK_A 0xffUL
3330#define DUK_BC_UNSHIFTED_MASK_B 0xffUL
3331#define DUK_BC_UNSHIFTED_MASK_C 0xffUL
3332#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL
3333#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL
3334
3335#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP)
3336#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A)
3337#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B)
3338#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C)
3339#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC)
3340#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC)
3341
3342#define DUK_DEC_OP(x) ((x) & 0xffUL)
3343#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL)
3344#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL)
3345#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL)
3346#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL)
3347#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL)
3348
3349#define DUK_ENC_OP(op) ((duk_instr_t) (op))
3350#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
3351 (((duk_instr_t) (abc)) << 8) | \
3352 ((duk_instr_t) (op)) \
3353 ))
3354#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
3355 (((duk_instr_t) (bc)) << 16) | \
3356 (((duk_instr_t) (a)) << 8) | \
3357 ((duk_instr_t) (op)) \
3358 ))
3359#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
3360 (((duk_instr_t) (c)) << 24) | \
3361 (((duk_instr_t) (b)) << 16) | \
3362 (((duk_instr_t) (a)) << 8) | \
3363 ((duk_instr_t) (op)) \
3364 ))
3365#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0)
3366#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0)
3367#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc))
3368
3369/* Get opcode base value with B/C reg/const flags cleared. */
3370#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc)
3371
3372/* Constants should be signed so that signed arithmetic involving them
3373 * won't cause values to be coerced accidentally to unsigned.
3374 */
3375#define DUK_BC_OP_MIN 0
3376#define DUK_BC_OP_MAX 0xffL
3377#define DUK_BC_A_MIN 0
3378#define DUK_BC_A_MAX 0xffL
3379#define DUK_BC_B_MIN 0
3380#define DUK_BC_B_MAX 0xffL
3381#define DUK_BC_C_MIN 0
3382#define DUK_BC_C_MAX 0xffL
3383#define DUK_BC_BC_MIN 0
3384#define DUK_BC_BC_MAX 0xffffL
3385#define DUK_BC_ABC_MIN 0
3386#define DUK_BC_ABC_MAX 0xffffffL
3387
3388/* Masks for B/C reg/const indicator in opcode field. */
3389#define DUK_BC_REGCONST_B (0x01UL)
3390#define DUK_BC_REGCONST_C (0x02UL)
3391
3392/* Misc. masks for opcode field. */
3393#define DUK_BC_INCDECP_FLAG_DEC (0x04UL)
3394#define DUK_BC_INCDECP_FLAG_POST (0x08UL)
3395
3396/* Opcodes. */
3397#define DUK_OP_LDREG 0
3398#define DUK_OP_STREG 1
3399#define DUK_OP_JUMP 2
3400#define DUK_OP_LDCONST 3
3401#define DUK_OP_LDINT 4
3402#define DUK_OP_LDINTX 5
3403#define DUK_OP_LDTHIS 6
3404#define DUK_OP_LDUNDEF 7
3405#define DUK_OP_LDNULL 8
3406#define DUK_OP_LDTRUE 9
3407#define DUK_OP_LDFALSE 10
3408#define DUK_OP_GETVAR 11
3409#define DUK_OP_BNOT 12
3410#define DUK_OP_LNOT 13
3411#define DUK_OP_UNM 14
3412#define DUK_OP_UNP 15
3413#define DUK_OP_EQ 16
3414#define DUK_OP_EQ_RR 16
3415#define DUK_OP_EQ_CR 17
3416#define DUK_OP_EQ_RC 18
3417#define DUK_OP_EQ_CC 19
3418#define DUK_OP_NEQ 20
3419#define DUK_OP_NEQ_RR 20
3420#define DUK_OP_NEQ_CR 21
3421#define DUK_OP_NEQ_RC 22
3422#define DUK_OP_NEQ_CC 23
3423#define DUK_OP_SEQ 24
3424#define DUK_OP_SEQ_RR 24
3425#define DUK_OP_SEQ_CR 25
3426#define DUK_OP_SEQ_RC 26
3427#define DUK_OP_SEQ_CC 27
3428#define DUK_OP_SNEQ 28
3429#define DUK_OP_SNEQ_RR 28
3430#define DUK_OP_SNEQ_CR 29
3431#define DUK_OP_SNEQ_RC 30
3432#define DUK_OP_SNEQ_CC 31
3433#define DUK_OP_GT 32
3434#define DUK_OP_GT_RR 32
3435#define DUK_OP_GT_CR 33
3436#define DUK_OP_GT_RC 34
3437#define DUK_OP_GT_CC 35
3438#define DUK_OP_GE 36
3439#define DUK_OP_GE_RR 36
3440#define DUK_OP_GE_CR 37
3441#define DUK_OP_GE_RC 38
3442#define DUK_OP_GE_CC 39
3443#define DUK_OP_LT 40
3444#define DUK_OP_LT_RR 40
3445#define DUK_OP_LT_CR 41
3446#define DUK_OP_LT_RC 42
3447#define DUK_OP_LT_CC 43
3448#define DUK_OP_LE 44
3449#define DUK_OP_LE_RR 44
3450#define DUK_OP_LE_CR 45
3451#define DUK_OP_LE_RC 46
3452#define DUK_OP_LE_CC 47
3453#define DUK_OP_IFTRUE 48
3454#define DUK_OP_IFTRUE_R 48
3455#define DUK_OP_IFTRUE_C 49
3456#define DUK_OP_IFFALSE 50
3457#define DUK_OP_IFFALSE_R 50
3458#define DUK_OP_IFFALSE_C 51
3459#define DUK_OP_ADD 52
3460#define DUK_OP_ADD_RR 52
3461#define DUK_OP_ADD_CR 53
3462#define DUK_OP_ADD_RC 54
3463#define DUK_OP_ADD_CC 55
3464#define DUK_OP_SUB 56
3465#define DUK_OP_SUB_RR 56
3466#define DUK_OP_SUB_CR 57
3467#define DUK_OP_SUB_RC 58
3468#define DUK_OP_SUB_CC 59
3469#define DUK_OP_MUL 60
3470#define DUK_OP_MUL_RR 60
3471#define DUK_OP_MUL_CR 61
3472#define DUK_OP_MUL_RC 62
3473#define DUK_OP_MUL_CC 63
3474#define DUK_OP_DIV 64
3475#define DUK_OP_DIV_RR 64
3476#define DUK_OP_DIV_CR 65
3477#define DUK_OP_DIV_RC 66
3478#define DUK_OP_DIV_CC 67
3479#define DUK_OP_MOD 68
3480#define DUK_OP_MOD_RR 68
3481#define DUK_OP_MOD_CR 69
3482#define DUK_OP_MOD_RC 70
3483#define DUK_OP_MOD_CC 71
3484#define DUK_OP_EXP 72
3485#define DUK_OP_EXP_RR 72
3486#define DUK_OP_EXP_CR 73
3487#define DUK_OP_EXP_RC 74
3488#define DUK_OP_EXP_CC 75
3489#define DUK_OP_BAND 76
3490#define DUK_OP_BAND_RR 76
3491#define DUK_OP_BAND_CR 77
3492#define DUK_OP_BAND_RC 78
3493#define DUK_OP_BAND_CC 79
3494#define DUK_OP_BOR 80
3495#define DUK_OP_BOR_RR 80
3496#define DUK_OP_BOR_CR 81
3497#define DUK_OP_BOR_RC 82
3498#define DUK_OP_BOR_CC 83
3499#define DUK_OP_BXOR 84
3500#define DUK_OP_BXOR_RR 84
3501#define DUK_OP_BXOR_CR 85
3502#define DUK_OP_BXOR_RC 86
3503#define DUK_OP_BXOR_CC 87
3504#define DUK_OP_BASL 88
3505#define DUK_OP_BASL_RR 88
3506#define DUK_OP_BASL_CR 89
3507#define DUK_OP_BASL_RC 90
3508#define DUK_OP_BASL_CC 91
3509#define DUK_OP_BLSR 92
3510#define DUK_OP_BLSR_RR 92
3511#define DUK_OP_BLSR_CR 93
3512#define DUK_OP_BLSR_RC 94
3513#define DUK_OP_BLSR_CC 95
3514#define DUK_OP_BASR 96
3515#define DUK_OP_BASR_RR 96
3516#define DUK_OP_BASR_CR 97
3517#define DUK_OP_BASR_RC 98
3518#define DUK_OP_BASR_CC 99
3519#define DUK_OP_INSTOF 100
3520#define DUK_OP_INSTOF_RR 100
3521#define DUK_OP_INSTOF_CR 101
3522#define DUK_OP_INSTOF_RC 102
3523#define DUK_OP_INSTOF_CC 103
3524#define DUK_OP_IN 104
3525#define DUK_OP_IN_RR 104
3526#define DUK_OP_IN_CR 105
3527#define DUK_OP_IN_RC 106
3528#define DUK_OP_IN_CC 107
3529#define DUK_OP_GETPROP 108
3530#define DUK_OP_GETPROP_RR 108
3531#define DUK_OP_GETPROP_CR 109
3532#define DUK_OP_GETPROP_RC 110
3533#define DUK_OP_GETPROP_CC 111
3534#define DUK_OP_PUTPROP 112
3535#define DUK_OP_PUTPROP_RR 112
3536#define DUK_OP_PUTPROP_CR 113
3537#define DUK_OP_PUTPROP_RC 114
3538#define DUK_OP_PUTPROP_CC 115
3539#define DUK_OP_DELPROP 116
3540#define DUK_OP_DELPROP_RR 116
3541#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */
3542#define DUK_OP_DELPROP_RC 118
3543#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */
3544#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */
3545#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */
3546#define DUK_OP_POSTINCR 122
3547#define DUK_OP_POSTDECR 123
3548#define DUK_OP_PREINCV 124
3549#define DUK_OP_PREDECV 125
3550#define DUK_OP_POSTINCV 126
3551#define DUK_OP_POSTDECV 127
3552#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */
3553#define DUK_OP_PREINCP_RR 128
3554#define DUK_OP_PREINCP_CR 129
3555#define DUK_OP_PREINCP_RC 130
3556#define DUK_OP_PREINCP_CC 131
3557#define DUK_OP_PREDECP 132
3558#define DUK_OP_PREDECP_RR 132
3559#define DUK_OP_PREDECP_CR 133
3560#define DUK_OP_PREDECP_RC 134
3561#define DUK_OP_PREDECP_CC 135
3562#define DUK_OP_POSTINCP 136
3563#define DUK_OP_POSTINCP_RR 136
3564#define DUK_OP_POSTINCP_CR 137
3565#define DUK_OP_POSTINCP_RC 138
3566#define DUK_OP_POSTINCP_CC 139
3567#define DUK_OP_POSTDECP 140
3568#define DUK_OP_POSTDECP_RR 140
3569#define DUK_OP_POSTDECP_CR 141
3570#define DUK_OP_POSTDECP_RC 142
3571#define DUK_OP_POSTDECP_CC 143
3572#define DUK_OP_DECLVAR 144
3573#define DUK_OP_DECLVAR_RR 144
3574#define DUK_OP_DECLVAR_CR 145
3575#define DUK_OP_DECLVAR_RC 146
3576#define DUK_OP_DECLVAR_CC 147
3577#define DUK_OP_REGEXP 148
3578#define DUK_OP_REGEXP_RR 148
3579#define DUK_OP_REGEXP_CR 149
3580#define DUK_OP_REGEXP_RC 150
3581#define DUK_OP_REGEXP_CC 151
3582#define DUK_OP_CLOSURE 152
3583#define DUK_OP_TYPEOF 153
3584#define DUK_OP_TYPEOFID 154
3585#define DUK_OP_PUTVAR 155
3586#define DUK_OP_DELVAR 156
3587#define DUK_OP_RETREG 157
3588#define DUK_OP_RETUNDEF 158
3589#define DUK_OP_RETCONST 159
3590#define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */
3591#define DUK_OP_LABEL 161
3592#define DUK_OP_ENDLABEL 162
3593#define DUK_OP_BREAK 163
3594#define DUK_OP_CONTINUE 164
3595#define DUK_OP_TRYCATCH 165
3596#define DUK_OP_ENDTRY 166
3597#define DUK_OP_ENDCATCH 167
3598#define DUK_OP_ENDFIN 168
3599#define DUK_OP_THROW 169
3600#define DUK_OP_INVLHS 170
3601#define DUK_OP_CSREG 171
3602#define DUK_OP_CSVAR 172
3603#define DUK_OP_CSVAR_RR 172
3604#define DUK_OP_CSVAR_CR 173
3605#define DUK_OP_CSVAR_RC 174
3606#define DUK_OP_CSVAR_CC 175
3607#define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */
3608#define DUK_OP_CALL1 177
3609#define DUK_OP_CALL2 178
3610#define DUK_OP_CALL3 179
3611#define DUK_OP_CALL4 180
3612#define DUK_OP_CALL5 181
3613#define DUK_OP_CALL6 182
3614#define DUK_OP_CALL7 183
3615#define DUK_OP_CALL8 184
3616#define DUK_OP_CALL9 185
3617#define DUK_OP_CALL10 186
3618#define DUK_OP_CALL11 187
3619#define DUK_OP_CALL12 188
3620#define DUK_OP_CALL13 189
3621#define DUK_OP_CALL14 190
3622#define DUK_OP_CALL15 191
3623#define DUK_OP_NEWOBJ 192
3624#define DUK_OP_NEWARR 193
3625#define DUK_OP_MPUTOBJ 194
3626#define DUK_OP_MPUTOBJI 195
3627#define DUK_OP_INITSET 196
3628#define DUK_OP_INITGET 197
3629#define DUK_OP_MPUTARR 198
3630#define DUK_OP_MPUTARRI 199
3631#define DUK_OP_SETALEN 200
3632#define DUK_OP_INITENUM 201
3633#define DUK_OP_NEXTENUM 202
3634#define DUK_OP_NEWTARGET 203
3635#define DUK_OP_DEBUGGER 204
3636#define DUK_OP_NOP 205
3637#define DUK_OP_INVALID 206
3638#define DUK_OP_UNUSED207 207
3639#define DUK_OP_GETPROPC 208
3640#define DUK_OP_GETPROPC_RR 208
3641#define DUK_OP_GETPROPC_CR 209
3642#define DUK_OP_GETPROPC_RC 210
3643#define DUK_OP_GETPROPC_CC 211
3644#define DUK_OP_UNUSED212 212
3645#define DUK_OP_UNUSED213 213
3646#define DUK_OP_UNUSED214 214
3647#define DUK_OP_UNUSED215 215
3648#define DUK_OP_UNUSED216 216
3649#define DUK_OP_UNUSED217 217
3650#define DUK_OP_UNUSED218 218
3651#define DUK_OP_UNUSED219 219
3652#define DUK_OP_UNUSED220 220
3653#define DUK_OP_UNUSED221 221
3654#define DUK_OP_UNUSED222 222
3655#define DUK_OP_UNUSED223 223
3656#define DUK_OP_UNUSED224 224
3657#define DUK_OP_UNUSED225 225
3658#define DUK_OP_UNUSED226 226
3659#define DUK_OP_UNUSED227 227
3660#define DUK_OP_UNUSED228 228
3661#define DUK_OP_UNUSED229 229
3662#define DUK_OP_UNUSED230 230
3663#define DUK_OP_UNUSED231 231
3664#define DUK_OP_UNUSED232 232
3665#define DUK_OP_UNUSED233 233
3666#define DUK_OP_UNUSED234 234
3667#define DUK_OP_UNUSED235 235
3668#define DUK_OP_UNUSED236 236
3669#define DUK_OP_UNUSED237 237
3670#define DUK_OP_UNUSED238 238
3671#define DUK_OP_UNUSED239 239
3672#define DUK_OP_UNUSED240 240
3673#define DUK_OP_UNUSED241 241
3674#define DUK_OP_UNUSED242 242
3675#define DUK_OP_UNUSED243 243
3676#define DUK_OP_UNUSED244 244
3677#define DUK_OP_UNUSED245 245
3678#define DUK_OP_UNUSED246 246
3679#define DUK_OP_UNUSED247 247
3680#define DUK_OP_UNUSED248 248
3681#define DUK_OP_UNUSED249 249
3682#define DUK_OP_UNUSED250 250
3683#define DUK_OP_UNUSED251 251
3684#define DUK_OP_UNUSED252 252
3685#define DUK_OP_UNUSED253 253
3686#define DUK_OP_UNUSED254 254
3687#define DUK_OP_UNUSED255 255
3688#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */
3689
3690/* XXX: Allocate flags from opcode field? Would take 16 opcode slots
3691 * but avoids shuffling in more cases. Maybe not worth it.
3692 */
3693/* DUK_OP_TRYCATCH flags in A. */
3694#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0)
3695#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1)
3696#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2)
3697#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3)
3698
3699/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags
3700 * (DUK_PROPDESC_FLAG_XXX).
3701 */
3702#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */
3703
3704/* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match
3705 * DUK_CALL_FLAG_xxx directly.
3706 */
3707#define DUK_BC_CALL_FLAG_TAILCALL (1U << 0)
3708#define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1)
3709#define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2)
3710#define DUK_BC_CALL_FLAG_INDIRECT (1U << 3)
3711
3712/* Misc constants and helper macros. */
3713#define DUK_BC_LDINT_BIAS (1L << 15)
3714#define DUK_BC_LDINTX_SHIFT 16
3715#define DUK_BC_JUMP_BIAS (1L << 23)
3716
3717#endif /* DUK_JS_BYTECODE_H_INCLUDED */
3718/* #include duk_lexer.h */
3719#line 1 "duk_lexer.h"
3720/*
3721 * Lexer defines.
3722 */
3723
3724#if !defined(DUK_LEXER_H_INCLUDED)
3725#define DUK_LEXER_H_INCLUDED
3726
3727typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
3728
3729/*
3730 * A token is interpreted as any possible production of InputElementDiv
3731 * and InputElementRegExp, see E5 Section 7 in its entirety. Note that
3732 * the E5 "Token" production does not cover all actual tokens of the
3733 * language (which is explicitly stated in the specification, Section 7.5).
3734 * Null and boolean literals are defined as part of both ReservedWord
3735 * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here,
3736 * null and boolean values have literal tokens, and are not reserved
3737 * words.
3738 *
3739 * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
3740 * The number tokens always have a non-negative value. The unary minus
3741 * operator in "-1.0" is optimized during compilation to yield a single
3742 * negative constant.
3743 *
3744 * Token numbering is free except that reserved words are required to be
3745 * in a continuous range and in a particular order. See genstrings.py.
3746 */
3747
3748#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx))
3749
3750#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
3751
3752#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt))
3753
3754/* Currently 6 characters of lookup are actually needed (duk_lexer.c). */
3755#define DUK_LEXER_WINDOW_SIZE 6
3756#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3757#define DUK_LEXER_BUFFER_SIZE 64
3758#endif
3759
3760#define DUK_TOK_MINVAL 0
3761
3762/* returned after EOF (infinite amount) */
3763#define DUK_TOK_EOF 0
3764
3765/* identifier names (E5 Section 7.6) */
3766#define DUK_TOK_IDENTIFIER 1
3767
3768/* reserved words: keywords */
3769#define DUK_TOK_START_RESERVED 2
3770#define DUK_TOK_BREAK 2
3771#define DUK_TOK_CASE 3
3772#define DUK_TOK_CATCH 4
3773#define DUK_TOK_CONTINUE 5
3774#define DUK_TOK_DEBUGGER 6
3775#define DUK_TOK_DEFAULT 7
3776#define DUK_TOK_DELETE 8
3777#define DUK_TOK_DO 9
3778#define DUK_TOK_ELSE 10
3779#define DUK_TOK_FINALLY 11
3780#define DUK_TOK_FOR 12
3781#define DUK_TOK_FUNCTION 13
3782#define DUK_TOK_IF 14
3783#define DUK_TOK_IN 15
3784#define DUK_TOK_INSTANCEOF 16
3785#define DUK_TOK_NEW 17
3786#define DUK_TOK_RETURN 18
3787#define DUK_TOK_SWITCH 19
3788#define DUK_TOK_THIS 20
3789#define DUK_TOK_THROW 21
3790#define DUK_TOK_TRY 22
3791#define DUK_TOK_TYPEOF 23
3792#define DUK_TOK_VAR 24
3793#define DUK_TOK_CONST 25
3794#define DUK_TOK_VOID 26
3795#define DUK_TOK_WHILE 27
3796#define DUK_TOK_WITH 28
3797
3798/* reserved words: future reserved words */
3799#define DUK_TOK_CLASS 29
3800#define DUK_TOK_ENUM 30
3801#define DUK_TOK_EXPORT 31
3802#define DUK_TOK_EXTENDS 32
3803#define DUK_TOK_IMPORT 33
3804#define DUK_TOK_SUPER 34
3805
3806/* "null", "true", and "false" are always reserved words.
3807 * Note that "get" and "set" are not!
3808 */
3809#define DUK_TOK_NULL 35
3810#define DUK_TOK_TRUE 36
3811#define DUK_TOK_FALSE 37
3812
3813/* reserved words: additional future reserved words in strict mode */
3814#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */
3815#define DUK_TOK_IMPLEMENTS 38
3816#define DUK_TOK_INTERFACE 39
3817#define DUK_TOK_LET 40
3818#define DUK_TOK_PACKAGE 41
3819#define DUK_TOK_PRIVATE 42
3820#define DUK_TOK_PROTECTED 43
3821#define DUK_TOK_PUBLIC 44
3822#define DUK_TOK_STATIC 45
3823#define DUK_TOK_YIELD 46
3824
3825#define DUK_TOK_END_RESERVED 47 /* exclusive */
3826
3827/* "get" and "set" are tokens but NOT ReservedWords. They are currently
3828 * parsed and identifiers and these defines are actually now unused.
3829 */
3830#define DUK_TOK_GET 47
3831#define DUK_TOK_SET 48
3832
3833/* punctuators (unlike the spec, also includes "/" and "/=") */
3834#define DUK_TOK_LCURLY 49
3835#define DUK_TOK_RCURLY 50
3836#define DUK_TOK_LBRACKET 51
3837#define DUK_TOK_RBRACKET 52
3838#define DUK_TOK_LPAREN 53
3839#define DUK_TOK_RPAREN 54
3840#define DUK_TOK_PERIOD 55
3841#define DUK_TOK_SEMICOLON 56
3842#define DUK_TOK_COMMA 57
3843#define DUK_TOK_LT 58
3844#define DUK_TOK_GT 59
3845#define DUK_TOK_LE 60
3846#define DUK_TOK_GE 61
3847#define DUK_TOK_EQ 62
3848#define DUK_TOK_NEQ 63
3849#define DUK_TOK_SEQ 64
3850#define DUK_TOK_SNEQ 65
3851#define DUK_TOK_ADD 66
3852#define DUK_TOK_SUB 67
3853#define DUK_TOK_MUL 68
3854#define DUK_TOK_DIV 69
3855#define DUK_TOK_MOD 70
3856#define DUK_TOK_EXP 71
3857#define DUK_TOK_INCREMENT 72
3858#define DUK_TOK_DECREMENT 73
3859#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */
3860#define DUK_TOK_ARSHIFT 75
3861#define DUK_TOK_RSHIFT 76
3862#define DUK_TOK_BAND 77
3863#define DUK_TOK_BOR 78
3864#define DUK_TOK_BXOR 79
3865#define DUK_TOK_LNOT 80
3866#define DUK_TOK_BNOT 81
3867#define DUK_TOK_LAND 82
3868#define DUK_TOK_LOR 83
3869#define DUK_TOK_QUESTION 84
3870#define DUK_TOK_COLON 85
3871#define DUK_TOK_EQUALSIGN 86
3872#define DUK_TOK_ADD_EQ 87
3873#define DUK_TOK_SUB_EQ 88
3874#define DUK_TOK_MUL_EQ 89
3875#define DUK_TOK_DIV_EQ 90
3876#define DUK_TOK_MOD_EQ 91
3877#define DUK_TOK_EXP_EQ 92
3878#define DUK_TOK_ALSHIFT_EQ 93
3879#define DUK_TOK_ARSHIFT_EQ 94
3880#define DUK_TOK_RSHIFT_EQ 95
3881#define DUK_TOK_BAND_EQ 96
3882#define DUK_TOK_BOR_EQ 97
3883#define DUK_TOK_BXOR_EQ 98
3884
3885/* literals (E5 Section 7.8), except null, true, false, which are treated
3886 * like reserved words (above).
3887 */
3888#define DUK_TOK_NUMBER 99
3889#define DUK_TOK_STRING 100
3890#define DUK_TOK_REGEXP 101
3891
3892#define DUK_TOK_MAXVAL 101 /* inclusive */
3893
3894#define DUK_TOK_INVALID DUK_SMALL_UINT_MAX
3895
3896/* Convert heap string index to a token (reserved words) */
3897#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
3898
3899/* Sanity check */
3900#if (DUK_TOK_MAXVAL > 255)
3901#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
3902#endif
3903
3904/* Sanity checks for string and token defines */
3905#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
3906#error mismatch in token defines
3907#endif
3908#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
3909#error mismatch in token defines
3910#endif
3911#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
3912#error mismatch in token defines
3913#endif
3914#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
3915#error mismatch in token defines
3916#endif
3917#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
3918#error mismatch in token defines
3919#endif
3920#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
3921#error mismatch in token defines
3922#endif
3923#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
3924#error mismatch in token defines
3925#endif
3926#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
3927#error mismatch in token defines
3928#endif
3929#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
3930#error mismatch in token defines
3931#endif
3932#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
3933#error mismatch in token defines
3934#endif
3935#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
3936#error mismatch in token defines
3937#endif
3938#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
3939#error mismatch in token defines
3940#endif
3941#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
3942#error mismatch in token defines
3943#endif
3944#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
3945#error mismatch in token defines
3946#endif
3947#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
3948#error mismatch in token defines
3949#endif
3950#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
3951#error mismatch in token defines
3952#endif
3953#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
3954#error mismatch in token defines
3955#endif
3956#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
3957#error mismatch in token defines
3958#endif
3959#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
3960#error mismatch in token defines
3961#endif
3962#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
3963#error mismatch in token defines
3964#endif
3965#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
3966#error mismatch in token defines
3967#endif
3968#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
3969#error mismatch in token defines
3970#endif
3971#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
3972#error mismatch in token defines
3973#endif
3974#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
3975#error mismatch in token defines
3976#endif
3977#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
3978#error mismatch in token defines
3979#endif
3980#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
3981#error mismatch in token defines
3982#endif
3983#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
3984#error mismatch in token defines
3985#endif
3986#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
3987#error mismatch in token defines
3988#endif
3989#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
3990#error mismatch in token defines
3991#endif
3992#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
3993#error mismatch in token defines
3994#endif
3995#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
3996#error mismatch in token defines
3997#endif
3998#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
3999#error mismatch in token defines
4000#endif
4001#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
4002#error mismatch in token defines
4003#endif
4004#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
4005#error mismatch in token defines
4006#endif
4007#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
4008#error mismatch in token defines
4009#endif
4010#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
4011#error mismatch in token defines
4012#endif
4013#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
4014#error mismatch in token defines
4015#endif
4016#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
4017#error mismatch in token defines
4018#endif
4019#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
4020#error mismatch in token defines
4021#endif
4022#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
4023#error mismatch in token defines
4024#endif
4025#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
4026#error mismatch in token defines
4027#endif
4028#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
4029#error mismatch in token defines
4030#endif
4031#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
4032#error mismatch in token defines
4033#endif
4034#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
4035#error mismatch in token defines
4036#endif
4037#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
4038#error mismatch in token defines
4039#endif
4040
4041/* Regexp tokens */
4042#define DUK_RETOK_EOF 0
4043#define DUK_RETOK_DISJUNCTION 1
4044#define DUK_RETOK_QUANTIFIER 2
4045#define DUK_RETOK_ASSERT_START 3
4046#define DUK_RETOK_ASSERT_END 4
4047#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5
4048#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6
4049#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7
4050#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
4051#define DUK_RETOK_ATOM_PERIOD 9
4052#define DUK_RETOK_ATOM_CHAR 10
4053#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */
4054#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */
4055#define DUK_RETOK_ATOM_WHITE 13 /* -""- */
4056#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */
4057#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */
4058#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */
4059#define DUK_RETOK_ATOM_BACKREFERENCE 17
4060#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
4061#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
4062#define DUK_RETOK_ATOM_START_CHARCLASS 20
4063#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21
4064#define DUK_RETOK_ATOM_END_GROUP 22
4065
4066/* Constants for duk_lexer_ctx.buf. */
4067#define DUK_LEXER_TEMP_BUF_LIMIT 256
4068
4069/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
4070 * Some fields (like num, str1, str2) are only valid for specific token types and may have
4071 * stale values otherwise.
4072 */
4073struct duk_token {
4074 duk_small_uint_t t; /* token type (with reserved word identification) */
4075 duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
4076 duk_double_t num; /* numeric value of token */
4077 duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
4078 duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
4079 duk_size_t start_offset; /* start byte offset of token in lexer input */
4080 duk_int_t start_line; /* start line of token (first char) */
4081 duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */
4082 duk_bool_t lineterm; /* token was preceded by a lineterm */
4083 duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */
4084};
4085
4086#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL)
4087
4088/* A regexp token value. */
4089struct duk_re_token {
4090 duk_small_uint_t t; /* token type */
4091 duk_small_uint_t greedy;
4092 duk_uint32_t num; /* numeric value (character, count) */
4093 duk_uint32_t qmin;
4094 duk_uint32_t qmax;
4095};
4096
4097/* A structure for 'snapshotting' a point for rewinding */
4098struct duk_lexer_point {
4099 duk_size_t offset;
4100 duk_int_t line;
4101};
4102
4103/* Lexer codepoint with additional info like offset/line number */
4104struct duk_lexer_codepoint {
4105 duk_codepoint_t codepoint;
4106 duk_size_t offset;
4107 duk_int_t line;
4108};
4109
4110/* Lexer context. Same context is used for ECMAScript and Regexp parsing. */
4111struct duk_lexer_ctx {
4112#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
4113 duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
4114 duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
4115#else
4116 duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
4117#endif
4118
4119 duk_hthread *thr; /* thread; minimizes argument passing */
4120
4121 const duk_uint8_t *input; /* input string (may be a user pointer) */
4122 duk_size_t input_length; /* input byte length */
4123 duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */
4124 duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */
4125
4126 duk_idx_t slot1_idx; /* valstack slot for 1st token value */
4127 duk_idx_t slot2_idx; /* valstack slot for 2nd token value */
4128 duk_idx_t buf_idx; /* valstack slot for temp buffer */
4129 duk_hbuffer_dynamic *buf; /* temp accumulation buffer */
4130 duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */
4131
4132 duk_int_t token_count; /* number of tokens parsed */
4133 duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
4134
4135 duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */
4136};
4137
4138/*
4139 * Prototypes
4140 */
4141
4142DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
4143
4144DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
4145DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
4146
4147DUK_INTERNAL_DECL
4148void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
4149 duk_token *out_token,
4150 duk_bool_t strict_mode,
4151 duk_bool_t regexp_mode);
4152#if defined(DUK_USE_REGEXP_SUPPORT)
4153DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
4154DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
4155#endif /* DUK_USE_REGEXP_SUPPORT */
4156
4157#endif /* DUK_LEXER_H_INCLUDED */
4158/* #include duk_js_compiler.h */
4159#line 1 "duk_js_compiler.h"
4160/*
4161 * ECMAScript compiler.
4162 */
4163
4164#if !defined(DUK_JS_COMPILER_H_INCLUDED)
4165#define DUK_JS_COMPILER_H_INCLUDED
4166
4167/* ECMAScript compiler limits */
4168#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
4169
4170/* maximum loopcount for peephole optimization */
4171#define DUK_COMPILER_PEEPHOLE_MAXITER 3
4172
4173/* maximum bytecode length in instructions */
4174#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */
4175
4176/*
4177 * Compiler intermediate values
4178 *
4179 * Intermediate values describe either plain values (e.g. strings or
4180 * numbers) or binary operations which have not yet been coerced into
4181 * either a left-hand-side or right-hand-side role (e.g. object property).
4182 */
4183
4184#define DUK_IVAL_NONE 0 /* no value */
4185#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
4186#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
4187#define DUK_IVAL_PROP 3 /* property access */
4188#define DUK_IVAL_VAR 4 /* variable access */
4189
4190#define DUK_ISPEC_NONE 0 /* no value */
4191#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
4192#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
4193
4194/* Bit mask which indicates that a regconst is a constant instead of a register.
4195 * Chosen so that when a regconst is cast to duk_int32_t, all consts are
4196 * negative values.
4197 */
4198#define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */
4199
4200/* Type to represent a reg/const reference during compilation, with <0
4201 * indicating a constant. Some call sites also use -1 to indicate 'none'.
4202 */
4203typedef duk_int32_t duk_regconst_t;
4204
4205typedef struct {
4206 duk_small_uint_t t; /* DUK_ISPEC_XXX */
4207 duk_regconst_t regconst;
4208 duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */
4209} duk_ispec;
4210
4211typedef struct {
4212 /*
4213 * PLAIN: x1
4214 * ARITH: x1 <op> x2
4215 * PROP: x1.x2
4216 * VAR: x1 (name)
4217 */
4218
4219 /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
4220 duk_small_uint_t t; /* DUK_IVAL_XXX */
4221 duk_small_uint_t op; /* bytecode opcode for binary ops */
4222 duk_ispec x1;
4223 duk_ispec x2;
4224} duk_ivalue;
4225
4226/*
4227 * Bytecode instruction representation during compilation
4228 *
4229 * Contains the actual instruction and (optionally) debug info.
4230 */
4231
4232struct duk_compiler_instr {
4233 duk_instr_t ins;
4234#if defined(DUK_USE_PC2LINE)
4235 duk_uint32_t line;
4236#endif
4237};
4238
4239/*
4240 * Compiler state
4241 */
4242
4243#define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0)
4244#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1)
4245
4246#define DUK_DECL_TYPE_VAR 0
4247#define DUK_DECL_TYPE_FUNC 1
4248
4249/* XXX: optimize to 16 bytes */
4250typedef struct {
4251 duk_small_uint_t flags;
4252 duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */
4253 duk_hstring *h_label; /* borrowed label name */
4254 duk_int_t catch_depth; /* catch depth at point of definition */
4255 duk_int_t pc_label; /* pc of label statement:
4256 * pc+1: break jump site
4257 * pc+2: continue jump site
4258 */
4259
4260 /* Fast jumps (which avoid longjmp) jump directly to the jump sites
4261 * which are always known even while the iteration/switch statement
4262 * is still being parsed. A final peephole pass "straightens out"
4263 * the jumps.
4264 */
4265} duk_labelinfo;
4266
4267/* Compiling state of one function, eventually converted to duk_hcompfunc */
4268struct duk_compiler_func {
4269 /* These pointers are at the start of the struct so that they pack
4270 * nicely. Mixing pointers and integer values is bad on some
4271 * platforms (e.g. if int is 32 bits and pointers are 64 bits).
4272 */
4273
4274 duk_bufwriter_ctx bw_code; /* bufwriter for code */
4275
4276 duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */
4277 /* h_code: held in bw_code */
4278 duk_hobject *h_consts; /* array */
4279 duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
4280 * offset/line points to closing brace to allow skipping on pass 2
4281 */
4282 duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ]
4283 * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
4284 * record function and variable declarations in pass 1
4285 */
4286 duk_hobject *h_labelnames; /* array of active label names */
4287 duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */
4288 duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
4289 duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
4290
4291 /* Value stack indices for tracking objects. */
4292 /* code_idx: not needed */
4293 duk_idx_t consts_idx;
4294 duk_idx_t funcs_idx;
4295 duk_idx_t decls_idx;
4296 duk_idx_t labelnames_idx;
4297 duk_idx_t labelinfos_idx;
4298 duk_idx_t argnames_idx;
4299 duk_idx_t varmap_idx;
4300
4301 /* Temp reg handling. */
4302 duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */
4303 duk_regconst_t temp_next; /* next temporary register to allocate */
4304 duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
4305
4306 /* Shuffle registers if large number of regs/consts. */
4307 duk_regconst_t shuffle1;
4308 duk_regconst_t shuffle2;
4309 duk_regconst_t shuffle3;
4310
4311 /* Stats for current expression being parsed. */
4312 duk_int_t nud_count;
4313 duk_int_t led_count;
4314 duk_int_t paren_level; /* parenthesis count, 0 = top level */
4315 duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
4316 duk_bool_t allow_in; /* current paren level allows 'in' token */
4317
4318 /* Misc. */
4319 duk_int_t stmt_next; /* statement id allocation (running counter) */
4320 duk_int_t label_next; /* label id allocation (running counter) */
4321 duk_int_t catch_depth; /* catch stack depth */
4322 duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
4323 duk_int_t fnum_next; /* inner function numbering */
4324 duk_int_t num_formals; /* number of formal arguments */
4325 duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
4326#if defined(DUK_USE_DEBUGGER_SUPPORT)
4327 duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
4328 duk_int_t max_line;
4329#endif
4330
4331 /* Status booleans. */
4332 duk_uint8_t is_function; /* is an actual function (not global/eval code) */
4333 duk_uint8_t is_eval; /* is eval code */
4334 duk_uint8_t is_global; /* is global code */
4335 duk_uint8_t is_namebinding; /* needs a name binding */
4336 duk_uint8_t is_constructable; /* result is constructable */
4337 duk_uint8_t is_setget; /* is a setter/getter */
4338 duk_uint8_t is_strict; /* function is strict */
4339 duk_uint8_t is_notail; /* function must not be tail called */
4340 duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
4341 duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */
4342 duk_uint8_t may_direct_eval; /* function may call direct eval */
4343 duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */
4344 duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */
4345 duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */
4346 duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
4347 duk_uint8_t needs_shuffle; /* function needs shuffle registers */
4348 duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
4349 duk_uint8_t allow_regexp_in_adv; /* allow RegExp literal on next advance() call */
4350};
4351
4352struct duk_compiler_ctx {
4353 duk_hthread *thr;
4354
4355 /* filename being compiled (ends up in functions' '_filename' property) */
4356 duk_hstring *h_filename; /* borrowed reference */
4357
4358 /* lexing (tokenization) state (contains two valstack slot indices) */
4359 duk_lexer_ctx lex;
4360
4361 /* current and previous token for parsing */
4362 duk_token prev_token;
4363 duk_token curr_token;
4364 duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */
4365 duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */
4366 duk_idx_t tok21_idx; /* prev_token slot1 */
4367 duk_idx_t tok22_idx; /* prev_token slot2 */
4368
4369 /* recursion limit */
4370 duk_int_t recursion_depth;
4371 duk_int_t recursion_limit;
4372
4373 /* code emission temporary */
4374 duk_int_t emit_jumpslot_pc;
4375
4376 /* current function being compiled (embedded instead of pointer for more compact access) */
4377 duk_compiler_func curr_func;
4378};
4379
4380/*
4381 * Prototypes
4382 */
4383
4384DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags);
4385
4386#endif /* DUK_JS_COMPILER_H_INCLUDED */
4387/* #include duk_regexp.h */
4388#line 1 "duk_regexp.h"
4389/*
4390 * Regular expression structs, constants, and bytecode defines.
4391 */
4392
4393#if !defined(DUK_REGEXP_H_INCLUDED)
4394#define DUK_REGEXP_H_INCLUDED
4395
4396/* maximum bytecode copies for {n,m} quantifiers */
4397#define DUK_RE_MAX_ATOM_COPIES 1000
4398
4399/* regexp compilation limits */
4400#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */
4401
4402/* regexp execution limits */
4403#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */
4404
4405/* regexp opcodes */
4406#define DUK_REOP_MATCH 1
4407#define DUK_REOP_CHAR 2
4408#define DUK_REOP_PERIOD 3
4409#define DUK_REOP_RANGES 4
4410#define DUK_REOP_INVRANGES 5
4411#define DUK_REOP_JUMP 6
4412#define DUK_REOP_SPLIT1 7
4413#define DUK_REOP_SPLIT2 8
4414#define DUK_REOP_SQMINIMAL 9
4415#define DUK_REOP_SQGREEDY 10
4416#define DUK_REOP_SAVE 11
4417#define DUK_REOP_WIPERANGE 12
4418#define DUK_REOP_LOOKPOS 13
4419#define DUK_REOP_LOOKNEG 14
4420#define DUK_REOP_BACKREFERENCE 15
4421#define DUK_REOP_ASSERT_START 16
4422#define DUK_REOP_ASSERT_END 17
4423#define DUK_REOP_ASSERT_WORD_BOUNDARY 18
4424#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
4425
4426/* flags */
4427#define DUK_RE_FLAG_GLOBAL (1U << 0)
4428#define DUK_RE_FLAG_IGNORE_CASE (1U << 1)
4429#define DUK_RE_FLAG_MULTILINE (1U << 2)
4430
4431struct duk_re_matcher_ctx {
4432 duk_hthread *thr;
4433
4434 duk_uint32_t re_flags;
4435 const duk_uint8_t *input;
4436 const duk_uint8_t *input_end;
4437 const duk_uint8_t *bytecode;
4438 const duk_uint8_t *bytecode_end;
4439 const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */
4440 duk_uint32_t nsaved;
4441 duk_uint32_t recursion_depth;
4442 duk_uint32_t recursion_limit;
4443 duk_uint32_t steps_count;
4444 duk_uint32_t steps_limit;
4445};
4446
4447struct duk_re_compiler_ctx {
4448 duk_hthread *thr;
4449
4450 duk_uint32_t re_flags;
4451 duk_lexer_ctx lex;
4452 duk_re_token curr_token;
4453 duk_bufwriter_ctx bw;
4454 duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */
4455 duk_uint32_t highest_backref;
4456 duk_uint32_t recursion_depth;
4457 duk_uint32_t recursion_limit;
4458 duk_uint32_t nranges; /* internal temporary value, used for char classes */
4459};
4460
4461/*
4462 * Prototypes
4463 */
4464
4465#if defined(DUK_USE_REGEXP_SUPPORT)
4466DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
4467DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
4468DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
4469DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
4470#endif
4471
4472#endif /* DUK_REGEXP_H_INCLUDED */
4473/* #include duk_heaphdr.h */
4474#line 1 "duk_heaphdr.h"
4475/*
4476 * Heap header definition and assorted macros, including ref counting.
4477 * Access all fields through the accessor macros.
4478 */
4479
4480#if !defined(DUK_HEAPHDR_H_INCLUDED)
4481#define DUK_HEAPHDR_H_INCLUDED
4482
4483/*
4484 * Common heap header
4485 *
4486 * All heap objects share the same flags and refcount fields. Objects other
4487 * than strings also need to have a single or double linked list pointers
4488 * for insertion into the "heap allocated" list. Strings have single linked
4489 * list pointers for string table chaining.
4490 *
4491 * Technically, 'h_refcount' must be wide enough to guarantee that it cannot
4492 * wrap; otherwise objects might be freed incorrectly after wrapping. The
4493 * default refcount field is 32 bits even on 64-bit systems: while that's in
4494 * theory incorrect, the Duktape heap needs to be larger than 64GB for the
4495 * count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely
4496 * to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes
4497 * Duktape to use size_t for refcounts which should always be safe.
4498 *
4499 * Heap header size on 32-bit platforms: 8 bytes without reference counting,
4500 * 16 bytes with reference counting.
4501 *
4502 * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
4503 * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
4504 * around them.
4505 */
4506
4507/* XXX: macro for shared header fields (avoids some padding issues) */
4508
4509struct duk_heaphdr {
4510 duk_uint32_t h_flags;
4511
4512#if defined(DUK_USE_REFERENCE_COUNTING)
4513#if defined(DUK_USE_ASSERTIONS)
4514 /* When assertions enabled, used by mark-and-sweep for refcount
4515 * validation. Largest reasonable type; also detects overflows.
4516 */
4517 duk_size_t h_assert_refcount;
4518#endif
4519#if defined(DUK_USE_REFCOUNT16)
4520 duk_uint16_t h_refcount;
4521#elif defined(DUK_USE_REFCOUNT32)
4522 duk_uint32_t h_refcount;
4523#else
4524 duk_size_t h_refcount;
4525#endif
4526#endif /* DUK_USE_REFERENCE_COUNTING */
4527
4528#if defined(DUK_USE_HEAPPTR16)
4529 duk_uint16_t h_next16;
4530#else
4531 duk_heaphdr *h_next;
4532#endif
4533
4534#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4535 /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
4536#if defined(DUK_USE_HEAPPTR16)
4537 duk_uint16_t h_prev16;
4538#else
4539 duk_heaphdr *h_prev;
4540#endif
4541#endif
4542
4543 /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
4544 * struct won't align nicely to 4 bytes. This 16-bit extra field
4545 * is added to make the alignment clean; the field can be used by
4546 * heap objects when 16-bit packing is used. This field is now
4547 * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
4548 * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
4549 * this only matter to low memory environments anyway.
4550 */
4551#if defined(DUK_USE_HEAPPTR16)
4552 duk_uint16_t h_extra16;
4553#endif
4554};
4555
4556struct duk_heaphdr_string {
4557 /* 16 bits would be enough for shared heaphdr flags and duk_hstring
4558 * flags. The initial parts of duk_heaphdr_string and duk_heaphdr
4559 * must match so changing the flags field size here would be quite
4560 * awkward. However, to minimize struct size, we can pack at least
4561 * 16 bits of duk_hstring data into the flags field.
4562 */
4563 duk_uint32_t h_flags;
4564
4565#if defined(DUK_USE_REFERENCE_COUNTING)
4566#if defined(DUK_USE_ASSERTIONS)
4567 /* When assertions enabled, used by mark-and-sweep for refcount
4568 * validation. Largest reasonable type; also detects overflows.
4569 */
4570 duk_size_t h_assert_refcount;
4571#endif
4572#if defined(DUK_USE_REFCOUNT16)
4573 duk_uint16_t h_refcount;
4574 duk_uint16_t h_strextra16; /* round out to 8 bytes */
4575#elif defined(DUK_USE_REFCOUNT32)
4576 duk_uint32_t h_refcount;
4577#else
4578 duk_size_t h_refcount;
4579#endif
4580#else
4581 duk_uint16_t h_strextra16;
4582#endif /* DUK_USE_REFERENCE_COUNTING */
4583
4584 duk_hstring *h_next;
4585 /* No 'h_prev' pointer for strings. */
4586};
4587
4588#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
4589#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
4590
4591 /* 2 bits for heap type */
4592#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
4593#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
4594
4595#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
4596#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
4597#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
4598#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
4599
4600#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
4601#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
4602#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
4603#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
4604#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
4605
4606#define DUK_HTYPE_MIN 0
4607#define DUK_HTYPE_STRING 0
4608#define DUK_HTYPE_OBJECT 1
4609#define DUK_HTYPE_BUFFER 2
4610#define DUK_HTYPE_MAX 2
4611
4612#if defined(DUK_USE_HEAPPTR16)
4613#define DUK_HEAPHDR_GET_NEXT(heap,h) \
4614 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
4615#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
4616 (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
4617 } while (0)
4618#else
4619#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
4620#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
4621 (h)->h_next = (val); \
4622 } while (0)
4623#endif
4624
4625#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4626#if defined(DUK_USE_HEAPPTR16)
4627#define DUK_HEAPHDR_GET_PREV(heap,h) \
4628 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
4629#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
4630 (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
4631 } while (0)
4632#else
4633#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
4634#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
4635 (h)->h_prev = (val); \
4636 } while (0)
4637#endif
4638#endif
4639
4640#if defined(DUK_USE_REFERENCE_COUNTING)
4641#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
4642#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
4643 (h)->h_refcount = (val); \
4644 DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \
4645 } while (0)
4646#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
4647#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
4648#else
4649/* refcount macros not defined without refcounting, caller must #if defined() now */
4650#endif /* DUK_USE_REFERENCE_COUNTING */
4651
4652/*
4653 * Note: type is treated as a field separate from flags, so some masking is
4654 * involved in the macros below.
4655 */
4656
4657#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
4658#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \
4659 (h)->h_flags = (val); } \
4660 }
4661#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
4662#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
4663 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
4664 } while (0)
4665#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
4666#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
4667 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
4668 } while (0)
4669
4670/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
4671 * and the comparison is unsigned, it's always true and generates warnings.
4672 */
4673#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
4674 DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
4675 )
4676
4677#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
4678 (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
4679 ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
4680 } while (0)
4681
4682#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
4683 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
4684 (h)->h_flags |= (bits); \
4685 } while (0)
4686
4687#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
4688 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
4689 (h)->h_flags &= ~((bits)); \
4690 } while (0)
4691
4692#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
4693
4694#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4695#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4696#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4697
4698#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4699#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4700#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4701
4702#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4703#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4704#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4705
4706#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4707#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4708#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4709
4710#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4711#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4712#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4713
4714/* get or set a range of flags; m=first bit number, n=number of bits */
4715#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
4716
4717#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
4718 (h)->h_flags = \
4719 ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
4720 | ((v) << (m)); \
4721 } while (0)
4722
4723/* init pointer fields to null */
4724#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4725#define DUK_HEAPHDR_INIT_NULLS(h) do { \
4726 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
4727 DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
4728 } while (0)
4729#else
4730#define DUK_HEAPHDR_INIT_NULLS(h) do { \
4731 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
4732 } while (0)
4733#endif
4734
4735#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \
4736 (h)->h_next = NULL; \
4737 } while (0)
4738
4739/*
4740 * Type tests
4741 */
4742
4743/* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit
4744 * is only set for DUK_HTYPE_OBJECT (= 1).
4745 */
4746#if 0
4747#define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
4748#endif
4749#define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL)
4750#define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
4751#define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
4752
4753/*
4754 * Assert helpers
4755 */
4756
4757/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
4758 * h->prev->next should point back to h.
4759 */
4760#if defined(DUK_USE_ASSERTIONS)
4761DUK_INTERNAL_DECL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h);
4762DUK_INTERNAL_DECL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h);
4763DUK_INTERNAL_DECL void duk_heaphdr_assert_valid(duk_heaphdr *h);
4764#define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do { duk_heaphdr_assert_links((heap), (h)); } while (0)
4765#define DUK_HEAPHDR_ASSERT_VALID(h) do { duk_heaphdr_assert_valid((h)); } while (0)
4766#else
4767#define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do {} while (0)
4768#define DUK_HEAPHDR_ASSERT_VALID(h) do {} while (0)
4769#endif
4770
4771#endif /* DUK_HEAPHDR_H_INCLUDED */
4772/* #include duk_refcount.h */
4773#line 1 "duk_refcount.h"
4774/*
4775 * Reference counting helper macros. The macros take a thread argument
4776 * and must thus always be executed in a specific thread context. The
4777 * thread argument is not really needed anymore: DECREF can operate with
4778 * a heap pointer only, and INCREF needs neither.
4779 */
4780
4781#if !defined(DUK_REFCOUNT_H_INCLUDED)
4782#define DUK_REFCOUNT_H_INCLUDED
4783
4784#if defined(DUK_USE_REFERENCE_COUNTING)
4785
4786#if defined(DUK_USE_ROM_OBJECTS)
4787/* With ROM objects "needs refcount update" is true when the value is
4788 * heap allocated and is not a ROM object.
4789 */
4790/* XXX: double evaluation for 'tv' argument. */
4791#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
4792 (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
4793#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h)))
4794#else /* DUK_USE_ROM_OBJECTS */
4795/* Without ROM objects "needs refcount update" == is heap allocated. */
4796#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv))
4797#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1
4798#endif /* DUK_USE_ROM_OBJECTS */
4799
4800/* Fast variants, inline refcount operations except for refzero handling.
4801 * Can be used explicitly when speed is always more important than size.
4802 * For a good compiler and a single file build, these are basically the
4803 * same as a forced inline.
4804 */
4805#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
4806 duk_tval *duk__tv = (tv); \
4807 DUK_ASSERT(duk__tv != NULL); \
4808 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4809 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4810 DUK_ASSERT(duk__h != NULL); \
4811 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4812 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4813 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
4814 } \
4815 } while (0)
4816#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
4817 duk_tval *duk__tv = (tv); \
4818 DUK_ASSERT(duk__tv != NULL); \
4819 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4820 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4821 DUK_ASSERT(duk__h != NULL); \
4822 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4823 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4824 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4825 duk_heaphdr_refzero((thr), duk__h); \
4826 } \
4827 } \
4828 } while (0)
4829#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \
4830 duk_tval *duk__tv = (tv); \
4831 DUK_ASSERT(duk__tv != NULL); \
4832 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4833 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4834 DUK_ASSERT(duk__h != NULL); \
4835 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4836 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4837 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4838 duk_heaphdr_refzero_norz((thr), duk__h); \
4839 } \
4840 } \
4841 } while (0)
4842#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
4843 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4844 DUK_ASSERT(duk__h != NULL); \
4845 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4846 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4847 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4848 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \
4849 } \
4850 } while (0)
4851#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \
4852 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4853 DUK_ASSERT(duk__h != NULL); \
4854 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4855 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4856 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4857 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4858 (rzcall)((thr), (rzcast) duk__h); \
4859 } \
4860 } \
4861 } while (0)
4862#define DUK_HEAPHDR_DECREF_FAST(thr,h) \
4863 DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4864#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \
4865 DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4866
4867/* Slow variants, call to a helper to reduce code size.
4868 * Can be used explicitly when size is always more important than speed.
4869 */
4870#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0)
4871#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0)
4872#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0)
4873#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4874#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4875#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4876#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4877#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4878#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4879#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4880#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4881#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4882#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4883#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4884#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4885
4886/* Default variants. Selection depends on speed/size preference.
4887 * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
4888 * is about +1kB for _FAST variants.
4889 */
4890#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4891/* XXX: It would be nice to specialize for specific duk_hobject subtypes
4892 * but current refzero queue handling prevents that.
4893 */
4894#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
4895#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
4896#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv))
4897#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
4898#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4899#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4900#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4901#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)
4902#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */
4903#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4904#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4905#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4906#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4907#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)
4908#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */
4909#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4910#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4911#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4912#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4913#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4914#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4915#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4916#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4917#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4918#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4919#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4920#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4921#else
4922#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
4923#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
4924#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv))
4925#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
4926#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
4927#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h))
4928#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4929#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h))
4930#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h))
4931#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4932#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h))
4933#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h))
4934#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4935#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h))
4936#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h))
4937#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4938#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4939#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4940#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4941#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4942#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4943#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4944#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4945#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4946#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4947#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4948#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4949#endif
4950
4951/* Convenience for some situations; the above macros don't allow NULLs
4952 * for performance reasons. Macros cover only actually needed cases.
4953 */
4954#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \
4955 if ((h) != NULL) { \
4956 DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
4957 } \
4958 } while (0)
4959#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \
4960 if ((h) != NULL) { \
4961 DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
4962 } \
4963 } while (0)
4964#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4965 if ((h) != NULL) { \
4966 DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \
4967 } \
4968 } while (0)
4969#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
4970 if ((h) != NULL) { \
4971 DUK_HOBJECT_INCREF((thr), (h)); \
4972 } \
4973 } while (0)
4974#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
4975 if ((h) != NULL) { \
4976 DUK_HOBJECT_DECREF((thr), (h)); \
4977 } \
4978 } while (0)
4979#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4980 if ((h) != NULL) { \
4981 DUK_HOBJECT_DECREF_NORZ((thr), (h)); \
4982 } \
4983 } while (0)
4984#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \
4985 if ((h) != NULL) { \
4986 DUK_HBUFFER_INCREF((thr), (h)); \
4987 } \
4988 } while (0)
4989#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \
4990 if ((h) != NULL) { \
4991 DUK_HBUFFER_DECREF((thr), (h)); \
4992 } \
4993 } while (0)
4994#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4995 if ((h) != NULL) { \
4996 DUK_HBUFFER_DECREF_NORZ((thr), (h)); \
4997 } \
4998 } while (0)
4999#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \
5000 if ((h) != NULL) { \
5001 DUK_HTHREAD_INCREF((thr), (h)); \
5002 } \
5003 } while (0)
5004#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \
5005 if ((h) != NULL) { \
5006 DUK_HTHREAD_DECREF((thr), (h)); \
5007 } \
5008 } while (0)
5009#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \
5010 if ((h) != NULL) { \
5011 DUK_HTHREAD_DECREF_NORZ((thr), (h)); \
5012 } \
5013 } while (0)
5014
5015/* Called after one or more DECREF NORZ calls to handle pending side effects.
5016 * At present DECREF NORZ does freeing inline but doesn't execute finalizers,
5017 * so these macros check for pending finalizers and execute them. The FAST
5018 * variant is performance critical.
5019 */
5020#if defined(DUK_USE_FINALIZER_SUPPORT)
5021#define DUK_REFZERO_CHECK_FAST(thr) do { \
5022 duk_refzero_check_fast((thr)); \
5023 } while (0)
5024#define DUK_REFZERO_CHECK_SLOW(thr) do { \
5025 duk_refzero_check_slow((thr)); \
5026 } while (0)
5027#else /* DUK_USE_FINALIZER_SUPPORT */
5028#define DUK_REFZERO_CHECK_FAST(thr) do { } while (0)
5029#define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0)
5030#endif /* DUK_USE_FINALIZER_SUPPORT */
5031
5032/*
5033 * Macros to set a duk_tval and update refcount of the target (decref the
5034 * old value and incref the new value if necessary). This is both performance
5035 * and footprint critical; any changes made should be measured for size/speed.
5036 */
5037
5038#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
5039 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5040 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5041 DUK_TVAL_SET_UNDEFINED(tv__dst); \
5042 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5043 } while (0)
5044
5045#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \
5046 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5047 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5048 DUK_TVAL_SET_UNDEFINED(tv__dst); \
5049 DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \
5050 } while (0)
5051
5052#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
5053 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5054 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5055 DUK_TVAL_SET_UNUSED(tv__dst); \
5056 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5057 } while (0)
5058
5059#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
5060 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5061 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5062 DUK_TVAL_SET_NULL(tv__dst); \
5063 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5064 } while (0)
5065
5066#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5067 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5068 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5069 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
5070 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5071 } while (0)
5072
5073#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5074 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5075 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5076 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
5077 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5078 } while (0)
5079#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5080 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5081 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5082 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
5083 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5084 } while (0)
5085#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5086 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5087 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5088 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
5089 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5090 } while (0)
5091#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
5092 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5093 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5094 DUK_TVAL_SET_NAN(tv__dst); \
5095 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5096 } while (0)
5097#if defined(DUK_USE_FASTINT)
5098#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5099 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5100 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5101 DUK_TVAL_SET_I48(tv__dst, (newval)); \
5102 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5103 } while (0)
5104#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5105 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5106 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5107 DUK_TVAL_SET_I32(tv__dst, (newval)); \
5108 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5109 } while (0)
5110#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5111 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5112 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5113 DUK_TVAL_SET_U32(tv__dst, (newval)); \
5114 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5115 } while (0)
5116#else
5117#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
5118 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
5119#endif /* DUK_USE_FASTINT */
5120
5121#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
5122 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5123 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5124 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
5125 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5126 } while (0)
5127
5128#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5129 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5130 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5131 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
5132 DUK_HSTRING_INCREF((thr), (newval)); \
5133 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5134 } while (0)
5135
5136#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5137 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5138 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5139 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
5140 DUK_HOBJECT_INCREF((thr), (newval)); \
5141 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5142 } while (0)
5143
5144#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5145 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5146 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5147 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
5148 DUK_HBUFFER_INCREF((thr), (newval)); \
5149 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5150 } while (0)
5151
5152#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5153 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5154 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5155 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
5156 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5157 } while (0)
5158
5159/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
5160 * etc, so it's very important for performance. Measure when changing.
5161 *
5162 * NOTE: the source and destination duk_tval pointers may be the same, and
5163 * the macros MUST deal with that correctly.
5164 */
5165
5166/* Original idiom used, minimal code size. */
5167#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
5168 duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
5169 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5170 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5171 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5172 DUK_TVAL_INCREF((thr), tv__src); \
5173 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
5174 } while (0)
5175
5176/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
5177 * fast incref/decref macros.
5178 */
5179#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
5180 duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
5181 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5182 DUK_TVAL_INCREF_FAST((thr), tv__src); \
5183 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
5184 h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
5185 DUK_ASSERT(h__obj != NULL); \
5186 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5187 DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
5188 } else { \
5189 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5190 } \
5191 } while (0)
5192
5193/* XXX: no optimized variants yet */
5194#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5195#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0
5196#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
5197#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
5198#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
5199#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
5200#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
5201#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
5202#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
5203#if defined(DUK_USE_FASTINT)
5204#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
5205#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
5206#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
5207#else
5208#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
5209#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5210#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5211#endif /* DUK_USE_FASTINT */
5212#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
5213#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
5214#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
5215#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
5216#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
5217#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
5218
5219#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
5220/* Optimized for speed. */
5221#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
5222#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
5223#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
5224#else
5225/* Optimized for size. */
5226#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
5227#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
5228#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
5229#endif
5230
5231#else /* DUK_USE_REFERENCE_COUNTING */
5232
5233#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0
5234#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0
5235
5236#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
5237#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
5238#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */
5239#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
5240#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
5241#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */
5242#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
5243#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
5244#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */
5245#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
5246#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
5247#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
5248#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
5249#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
5250#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
5251#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
5252#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
5253#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5254#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */
5255#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */
5256#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
5257#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */
5258#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */
5259#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
5260#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
5261#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
5262#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5263#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */
5264#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */
5265#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
5266#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */
5267#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */
5268#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
5269#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
5270#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
5271#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5272#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */
5273#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */
5274#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
5275#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */
5276#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */
5277#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
5278#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
5279#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
5280#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5281
5282#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */
5283#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */
5284#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5285#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */
5286#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */
5287#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5288#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */
5289#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */
5290#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5291#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
5292#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
5293#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */
5294#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
5295#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
5296#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
5297#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
5298#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
5299#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
5300
5301#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */
5302#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */
5303
5304#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
5305 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5306 DUK_TVAL_SET_UNDEFINED(tv__dst); \
5307 DUK_UNREF((thr)); \
5308 } while (0)
5309
5310#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
5311 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5312 DUK_TVAL_SET_UNUSED(tv__dst); \
5313 DUK_UNREF((thr)); \
5314 } while (0)
5315
5316#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
5317 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5318 DUK_TVAL_SET_NULL(tv__dst); \
5319 DUK_UNREF((thr)); \
5320 } while (0)
5321
5322#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5323 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5324 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
5325 DUK_UNREF((thr)); \
5326 } while (0)
5327
5328#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5329 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5330 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
5331 DUK_UNREF((thr)); \
5332 } while (0)
5333#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5334 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5335 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
5336 DUK_UNREF((thr)); \
5337 } while (0)
5338#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5339 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5340 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
5341 DUK_UNREF((thr)); \
5342 } while (0)
5343#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
5344 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5345 DUK_TVAL_SET_NAN(tv__dst); \
5346 DUK_UNREF((thr)); \
5347 } while (0)
5348#if defined(DUK_USE_FASTINT)
5349#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5350 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5351 DUK_TVAL_SET_I48(tv__dst, (newval)); \
5352 DUK_UNREF((thr)); \
5353 } while (0)
5354#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5355 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5356 DUK_TVAL_SET_I32(tv__dst, (newval)); \
5357 DUK_UNREF((thr)); \
5358 } while (0)
5359#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5360 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5361 DUK_TVAL_SET_U32(tv__dst, (newval)); \
5362 DUK_UNREF((thr)); \
5363 } while (0)
5364#else
5365#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
5366 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
5367#endif /* DUK_USE_FASTINT */
5368
5369#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
5370 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5371 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
5372 DUK_UNREF((thr)); \
5373 } while (0)
5374
5375#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5376 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5377 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
5378 DUK_UNREF((thr)); \
5379 } while (0)
5380
5381#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5382 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5383 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
5384 DUK_UNREF((thr)); \
5385 } while (0)
5386
5387#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5388 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5389 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
5390 DUK_UNREF((thr)); \
5391 } while (0)
5392
5393#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5394 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5395 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
5396 DUK_UNREF((thr)); \
5397 } while (0)
5398
5399#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
5400 duk_tval *tv__dst, *tv__src; \
5401 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5402 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5403 DUK_UNREF((thr)); \
5404 } while (0)
5405
5406#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5407#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5408#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
5409#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
5410#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
5411#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
5412#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
5413#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
5414#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
5415#if defined(DUK_USE_FASTINT)
5416#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
5417#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
5418#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
5419#else
5420#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
5421#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5422#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5423#endif /* DUK_USE_FASTINT */
5424#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
5425#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
5426#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
5427#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
5428#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
5429#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
5430
5431#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
5432#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
5433#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
5434
5435#endif /* DUK_USE_REFERENCE_COUNTING */
5436
5437/*
5438 * Some convenience macros that don't have optimized implementations now.
5439 */
5440
5441#define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \
5442 duk_hthread *duk__thr = (thr); \
5443 duk_tval *duk__dst = (tv_dst); \
5444 duk_tval *duk__src = (tv_src); \
5445 DUK_UNREF(duk__thr); \
5446 DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
5447 DUK_TVAL_SET_TVAL(duk__dst, duk__src); \
5448 DUK_TVAL_INCREF(thr, duk__dst); \
5449 } while (0)
5450
5451#define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \
5452 duk_hthread *duk__thr = (thr); \
5453 duk_tval *duk__dst = (tv_dst); \
5454 duk_uint32_t duk__val = (duk_uint32_t) (val); \
5455 DUK_UNREF(duk__thr); \
5456 DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
5457 DUK_TVAL_SET_U32(duk__dst, duk__val); \
5458 } while (0)
5459
5460/*
5461 * Prototypes
5462 */
5463
5464#if defined(DUK_USE_REFERENCE_COUNTING)
5465#if defined(DUK_USE_FINALIZER_SUPPORT)
5466DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr);
5467DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr);
5468#endif
5469DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr);
5470DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h);
5471#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */
5472DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h);
5473DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h);
5474DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h);
5475DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h);
5476DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h);
5477DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h);
5478#endif
5479DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
5480DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h);
5481#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
5482DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */
5483DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */
5484DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h);
5485DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h);
5486#else
5487DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
5488DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
5489DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv);
5490DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
5491DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
5492DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h);
5493#endif
5494#else /* DUK_USE_REFERENCE_COUNTING */
5495/* no refcounting */
5496#endif /* DUK_USE_REFERENCE_COUNTING */
5497
5498#endif /* DUK_REFCOUNT_H_INCLUDED */
5499/* #include duk_api_internal.h */
5500#line 1 "duk_api_internal.h"
5501/*
5502 * Internal API calls which have (stack and other) semantics similar
5503 * to the public API.
5504 */
5505
5506#if !defined(DUK_API_INTERNAL_H_INCLUDED)
5507#define DUK_API_INTERNAL_H_INCLUDED
5508
5509/* Inline macro helpers. */
5510#if defined(DUK_USE_PREFER_SIZE)
5511#define DUK_INLINE_PERF
5512#define DUK_ALWAYS_INLINE_PERF
5513#define DUK_NOINLINE_PERF
5514#else
5515#define DUK_INLINE_PERF DUK_INLINE
5516#define DUK_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE
5517#define DUK_NOINLINE_PERF DUK_NOINLINE
5518#endif
5519
5520/* Inline macro helpers, for bytecode executor. */
5521#if defined(DUK_USE_EXEC_PREFER_SIZE)
5522#define DUK_EXEC_INLINE_PERF
5523#define DUK_EXEC_ALWAYS_INLINE_PERF
5524#define DUK_EXEC_NOINLINE_PERF
5525#else
5526#define DUK_EXEC_INLINE_PERF DUK_INLINE
5527#define DUK_EXEC_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE
5528#define DUK_EXEC_NOINLINE_PERF DUK_NOINLINE
5529#endif
5530
5531/* duk_push_sprintf constants */
5532#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
5533#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
5534
5535/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
5536 * blamed as source of error for error fileName / lineNumber.
5537 */
5538#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
5539
5540/* Current convention is to use duk_size_t for value stack sizes and global indices,
5541 * and duk_idx_t for local frame indices.
5542 */
5543DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
5544DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
5545DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
5546
5547DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
5548
5549DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
5550
5551DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
5552DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
5553
5554DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
5555DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
5556DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
5557/* duk_dup_m1() would be same as duk_dup_top() */
5558DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
5559DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
5560DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
5561
5562DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
5563DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
5564DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5565DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5566
5567DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
5568DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
5569
5570#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
5571DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
5572#endif
5573DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
5574
5575DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
5576DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
5577DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
5578DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
5579
5580/* Push the current 'this' binding; throw TypeError if binding is not object
5581 * coercible (CheckObjectCoercible).
5582 */
5583DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
5584
5585/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
5586DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
5587
5588/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
5589DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
5590
5591DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
5592
5593/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
5594 * make sure there's an active callstack entry. Note that the returned pointer
5595 * is unstable with regards to side effects.
5596 */
5597DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
5598
5599/* XXX: add fastint support? */
5600#define duk_push_u64(thr,val) \
5601 duk_push_number((thr), (duk_double_t) (val))
5602#define duk_push_i64(thr,val) \
5603 duk_push_number((thr), (duk_double_t) (val))
5604
5605/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
5606#define duk_push_u32(thr,val) \
5607 duk_push_uint((thr), (duk_uint_t) (val))
5608#define duk_push_i32(thr,val) \
5609 duk_push_int((thr), (duk_int_t) (val))
5610
5611/* sometimes stack and array indices need to go on the stack */
5612#define duk_push_idx(thr,val) \
5613 duk_push_int((thr), (duk_int_t) (val))
5614#define duk_push_uarridx(thr,val) \
5615 duk_push_uint((thr), (duk_uint_t) (val))
5616#define duk_push_size_t(thr,val) \
5617 duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
5618
5619DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5620
5621DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
5622
5623DUK_INTERNAL_DECL duk_bool_t duk_is_bare_object(duk_hthread *thr, duk_idx_t idx);
5624
5625DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
5626DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
5627DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5628DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
5629DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
5630DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
5631DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5632DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5633
5634DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer);
5635
5636DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
5637
5638DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5639DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5640DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5641#define duk_require_hobject_promote_lfunc(thr,idx) \
5642 duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
5643#define duk_get_hobject_promote_lfunc(thr,idx) \
5644 duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
5645
5646#if 0 /*unused*/
5647DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
5648#endif
5649
5650DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
5651DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
5652DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
5653DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5654DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5655
5656DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
5657
5658DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
5659DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
5660DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
5661
5662DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
5663
5664DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
5665DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
5666
5667DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr);
5668
5669#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
5670DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
5671#endif
5672DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects);
5673
5674DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
5675DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
5676DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
5677#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5678DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
5679#endif
5680DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
5681
5682DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
5683DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
5684DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
5685DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5686DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
5687DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
5688DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
5689DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5690DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5691
5692DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
5693
5694DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
5695DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
5696DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
5697DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
5698DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
5699#define duk_push_hthread(thr,h) \
5700 duk_push_hobject((thr), (duk_hobject *) (h))
5701#define duk_push_hnatfunc(thr,h) \
5702 duk_push_hobject((thr), (duk_hobject *) (h))
5703DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
5704DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
5705DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
5706DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
5707DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
5708DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
5709DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
5710
5711/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
5712 * duk_push_hobject() etc which don't create a new value.
5713 */
5714DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
5715DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
5716DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
5717
5718DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
5719DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
5720DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
5721DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
5722#if 0 /* not used yet */
5723DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
5724#endif
5725#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5726DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
5727#endif
5728
5729DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
5730DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
5731
5732DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
5733DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
5734DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
5735
5736/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
5737 * enough to be packed into a single 32-bit integer argument. Argument limits
5738 * vary per call; typically 16 bits are assigned to the signed value stack index
5739 * and the stridx. In practice these work well for footprint with constant
5740 * arguments and such call sites are also easiest to verify to be correct.
5741 */
5742
5743DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
5744DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5745#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
5746 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
5747 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5748 duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5749DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
5750
5751DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop(duk_hthread *thr, duk_idx_t obj_idx);
5752DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);
5753DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5754#define duk_xget_owndataprop_stridx_short(thr,obj_idx,stridx) \
5755 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
5756 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5757 duk_xget_owndataprop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5758
5759DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
5760DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5761#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
5762 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
5763 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5764 duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5765
5766DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
5767#if 0 /* Too few call sites to be useful. */
5768DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5769#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
5770 (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
5771 DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
5772 duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5773#endif
5774#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
5775 duk_del_prop_stridx((thr), (obj_idx), (stridx))
5776
5777DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
5778#if 0 /* Too few call sites to be useful. */
5779DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5780#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
5781 (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
5782 DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
5783 duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5784#endif
5785#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
5786 duk_has_prop_stridx((thr), (obj_idx), (stridx))
5787
5788DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
5789
5790DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
5791
5792/* XXX: Because stridx and desc_flags have a limited range, this call could
5793 * always pack stridx and desc_flags into a single argument.
5794 */
5795DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
5796DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5797#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
5798 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
5799 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5800 DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
5801 duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
5802
5803#define duk_xdef_prop_wec(thr,obj_idx) \
5804 duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
5805#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
5806 duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
5807#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
5808 duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
5809#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
5810 duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
5811
5812#if 0 /*unused*/
5813DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
5814#endif
5815
5816DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
5817
5818DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx);
5819
5820DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
5821DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
5822#if 0
5823DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
5824#endif
5825
5826DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
5827
5828DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
5829
5830DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
5831DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
5832
5833DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
5834DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
5835DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
5836DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
5837DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
5838DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
5839DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
5840DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
5841DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
5842
5843DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
5844
5845DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
5846
5847DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
5848DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5849
5850DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
5851
5852DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
5853
5854#if defined(DUK_USE_SYMBOL_BUILTIN)
5855DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint);
5856#endif
5857
5858DUK_INTERNAL_DECL void duk_clear_prototype(duk_hthread *thr, duk_idx_t idx);
5859
5860/* Raw internal valstack access macros: access is unsafe so call site
5861 * must have a guarantee that the index is valid. When that is the case,
5862 * using these macro results in faster and smaller code than duk_get_tval().
5863 * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
5864 */
5865#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
5866 (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
5867#define DUK_ASSERT_VALID_POSIDX(thr,idx) \
5868 (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
5869#define DUK_GET_TVAL_NEGIDX(thr,idx) \
5870 (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
5871#define DUK_GET_TVAL_POSIDX(thr,idx) \
5872 (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
5873#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
5874 (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
5875#define DUK_GET_HOBJECT_POSIDX(thr,idx) \
5876 (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
5877
5878#define DUK_GET_THIS_TVAL_PTR(thr) \
5879 (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
5880 (thr)->valstack_bottom - 1)
5881
5882DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
5883DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
5884DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
5885
5886#endif /* DUK_API_INTERNAL_H_INCLUDED */
5887/* #include duk_hstring.h */
5888#line 1 "duk_hstring.h"
5889/*
5890 * Heap string representation.
5891 *
5892 * Strings are byte sequences ordinarily stored in extended UTF-8 format,
5893 * allowing values larger than the official UTF-8 range (used internally)
5894 * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
5895 * Strings may also be invalid UTF-8 altogether which is the case e.g. with
5896 * strings used as internal property names and raw buffers converted to
5897 * strings. In such cases the 'clen' field contains an inaccurate value.
5898 *
5899 * ECMAScript requires support for 32-bit long strings. However, since each
5900 * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
5901 * support about 1.4G codepoint long strings in extreme cases. This is not
5902 * really a practical issue.
5903 */
5904
5905#if !defined(DUK_HSTRING_H_INCLUDED)
5906#define DUK_HSTRING_H_INCLUDED
5907
5908/* Impose a maximum string length for now. Restricted artificially to
5909 * ensure adding a heap header length won't overflow size_t. The limit
5910 * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
5911 *
5912 * E5.1 makes provisions to support strings longer than 4G characters.
5913 * This limit should be eliminated on 64-bit platforms (and increased
5914 * closer to maximum support on 32-bit platforms).
5915 */
5916
5917#if defined(DUK_USE_STRLEN16)
5918#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL)
5919#else
5920#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
5921#endif
5922
5923/* XXX: could add flags for "is valid CESU-8" (ECMAScript compatible strings),
5924 * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
5925 * regexp bytecode is), and "contains non-BMP characters". These are not
5926 * needed right now.
5927 */
5928
5929/* With lowmem builds the high 16 bits of duk_heaphdr are used for other
5930 * purposes, so this leaves 7 duk_heaphdr flags and 9 duk_hstring flags.
5931 */
5932#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
5933#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
5934#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */
5935#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */
5936#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */
5937#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */
5938#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */
5939#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */
5940#define DUK_HSTRING_FLAG_PINNED_LITERAL DUK_HEAPHDR_USER_FLAG(8) /* string is a literal, and pinned */
5941
5942#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5943#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5944#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5945#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5946#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5947#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5948#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5949#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5950#define DUK_HSTRING_HAS_PINNED_LITERAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5951
5952#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5953#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5954#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5955#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5956#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5957#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5958#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5959#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5960#define DUK_HSTRING_SET_PINNED_LITERAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5961
5962#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5963#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5964#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5965#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5966#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5967#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5968#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5969#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5970#define DUK_HSTRING_CLEAR_PINNED_LITERAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5971
5972#if 0 /* Slightly smaller code without explicit flag, but explicit flag
5973 * is very useful when 'clen' is dropped.
5974 */
5975#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
5976#endif
5977#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */
5978#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
5979
5980#if defined(DUK_USE_STRHASH16)
5981#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16)
5982#define DUK_HSTRING_SET_HASH(x,v) do { \
5983 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
5984 } while (0)
5985#else
5986#define DUK_HSTRING_GET_HASH(x) ((x)->hash)
5987#define DUK_HSTRING_SET_HASH(x,v) do { \
5988 (x)->hash = (v); \
5989 } while (0)
5990#endif
5991
5992#if defined(DUK_USE_STRLEN16)
5993#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16)
5994#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
5995 (x)->hdr.h_strextra16 = (v); \
5996 } while (0)
5997#if defined(DUK_USE_HSTRING_CLEN)
5998#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
5999#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
6000 (x)->clen16 = (v); \
6001 } while (0)
6002#else
6003#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
6004#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
6005 DUK_ASSERT(0); /* should never be called */ \
6006 } while (0)
6007#endif
6008#else
6009#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen)
6010#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
6011 (x)->blen = (v); \
6012 } while (0)
6013#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
6014#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
6015 (x)->clen = (v); \
6016 } while (0)
6017#endif
6018
6019#if defined(DUK_USE_HSTRING_EXTDATA)
6020#define DUK_HSTRING_GET_EXTDATA(x) \
6021 ((x)->extdata)
6022#define DUK_HSTRING_GET_DATA(x) \
6023 (DUK_HSTRING_HAS_EXTDATA((x)) ? \
6024 DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
6025#else
6026#define DUK_HSTRING_GET_DATA(x) \
6027 ((const duk_uint8_t *) ((x) + 1))
6028#endif
6029
6030#define DUK_HSTRING_GET_DATA_END(x) \
6031 (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
6032
6033/* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest
6034 * valid).
6035 */
6036#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
6037
6038#if defined(DUK_USE_HSTRING_ARRIDX)
6039#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx)
6040#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx)
6041#else
6042/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
6043 * avoids helper call if string has no array index value.
6044 */
6045#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
6046 (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
6047
6048/* Slower but more compact variant. */
6049#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
6050 (duk_js_to_arrayindex_hstring_fast((h)))
6051#endif
6052
6053/* XXX: these actually fit into duk_hstring */
6054#define DUK_SYMBOL_TYPE_HIDDEN 0
6055#define DUK_SYMBOL_TYPE_GLOBAL 1
6056#define DUK_SYMBOL_TYPE_LOCAL 2
6057#define DUK_SYMBOL_TYPE_WELLKNOWN 3
6058
6059/* Assertion for duk_hstring validity. */
6060#if defined(DUK_USE_ASSERTIONS)
6061DUK_INTERNAL_DECL void duk_hstring_assert_valid(duk_hstring *h);
6062#define DUK_HSTRING_ASSERT_VALID(h) do { duk_hstring_assert_valid((h)); } while (0)
6063#else
6064#define DUK_HSTRING_ASSERT_VALID(h) do {} while (0)
6065#endif
6066
6067/*
6068 * Misc
6069 */
6070
6071struct duk_hstring {
6072 /* Smaller heaphdr than for other objects, because strings are held
6073 * in string intern table which requires no link pointers. Much of
6074 * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
6075 * field in there.
6076 */
6077 duk_heaphdr_string hdr;
6078
6079 /* String hash. */
6080#if defined(DUK_USE_STRHASH16)
6081 /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
6082#else
6083 duk_uint32_t hash;
6084#endif
6085
6086 /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */
6087#if defined(DUK_USE_HSTRING_ARRIDX)
6088 duk_uarridx_t arridx;
6089#endif
6090
6091 /* Length in bytes (not counting NUL term). */
6092#if defined(DUK_USE_STRLEN16)
6093 /* placed in duk_heaphdr_string */
6094#else
6095 duk_uint32_t blen;
6096#endif
6097
6098 /* Length in codepoints (must be E5 compatible). */
6099#if defined(DUK_USE_STRLEN16)
6100#if defined(DUK_USE_HSTRING_CLEN)
6101 duk_uint16_t clen16;
6102#else
6103 /* computed live */
6104#endif
6105#else
6106 duk_uint32_t clen;
6107#endif
6108
6109 /*
6110 * String data of 'blen+1' bytes follows (+1 for NUL termination
6111 * convenience for C API). No alignment needs to be guaranteed
6112 * for strings, but fields above should guarantee alignment-by-4
6113 * (but not alignment-by-8).
6114 */
6115};
6116
6117/* The external string struct is defined even when the feature is inactive. */
6118struct duk_hstring_external {
6119 duk_hstring str;
6120
6121 /*
6122 * For an external string, the NUL-terminated string data is stored
6123 * externally. The user must guarantee that data behind this pointer
6124 * doesn't change while it's used.
6125 */
6126
6127 const duk_uint8_t *extdata;
6128};
6129
6130/*
6131 * Prototypes
6132 */
6133
6134DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware);
6135DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr);
6136DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
6137#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
6138DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
6139#endif
6140
6141#endif /* DUK_HSTRING_H_INCLUDED */
6142/* #include duk_hobject.h */
6143#line 1 "duk_hobject.h"
6144/*
6145 * Heap object representation.
6146 *
6147 * Heap objects are used for ECMAScript objects, arrays, and functions,
6148 * but also for internal control like declarative and object environment
6149 * records. Compiled functions, native functions, and threads are also
6150 * objects but with an extended C struct.
6151 *
6152 * Objects provide the required ECMAScript semantics and exotic behaviors
6153 * especially for property access.
6154 *
6155 * Properties are stored in three conceptual parts:
6156 *
6157 * 1. A linear 'entry part' contains ordered key-value-attributes triples
6158 * and is the main method of string properties.
6159 *
6160 * 2. An optional linear 'array part' is used for array objects to store a
6161 * (dense) range of [0,N[ array indexed entries with default attributes
6162 * (writable, enumerable, configurable). If the array part would become
6163 * sparse or non-default attributes are required, the array part is
6164 * abandoned and moved to the 'entry part'.
6165 *
6166 * 3. An optional 'hash part' is used to optimize lookups of the entry
6167 * part; it is used only for objects with sufficiently many properties
6168 * and can be abandoned without loss of information.
6169 *
6170 * These three conceptual parts are stored in a single memory allocated area.
6171 * This minimizes memory allocation overhead but also means that all three
6172 * parts are resized together, and makes property access a bit complicated.
6173 */
6174
6175#if !defined(DUK_HOBJECT_H_INCLUDED)
6176#define DUK_HOBJECT_H_INCLUDED
6177
6178/* Object flags. Make sure this stays in sync with debugger object
6179 * inspection code.
6180 */
6181
6182/* XXX: some flags are object subtype specific (e.g. common to all function
6183 * subtypes, duk_harray, etc) and could be reused for different subtypes.
6184 */
6185#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
6186#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
6187#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */
6188#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */
6189#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
6190#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
6191#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
6192#define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */
6193#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
6194#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
6195#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
6196#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
6197#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
6198#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
6199#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */
6200#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
6201#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
6202#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
6203#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
6204#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */
6205
6206#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
6207#define DUK_HOBJECT_FLAG_CLASS_BITS 5
6208
6209#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
6210 DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
6211#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
6212 DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
6213
6214#define DUK_HOBJECT_GET_CLASS_MASK(h) \
6215 (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
6216
6217/* Macro for creating flag initializer from a class number.
6218 * Unsigned type cast is needed to avoid warnings about coercing
6219 * a signed integer to an unsigned one; the largest class values
6220 * have the highest bit (bit 31) set which causes this.
6221 */
6222#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
6223
6224/* E5 Section 8.6.2 + custom classes */
6225#define DUK_HOBJECT_CLASS_NONE 0
6226#define DUK_HOBJECT_CLASS_OBJECT 1
6227#define DUK_HOBJECT_CLASS_ARRAY 2
6228#define DUK_HOBJECT_CLASS_FUNCTION 3
6229#define DUK_HOBJECT_CLASS_ARGUMENTS 4
6230#define DUK_HOBJECT_CLASS_BOOLEAN 5
6231#define DUK_HOBJECT_CLASS_DATE 6
6232#define DUK_HOBJECT_CLASS_ERROR 7
6233#define DUK_HOBJECT_CLASS_JSON 8
6234#define DUK_HOBJECT_CLASS_MATH 9
6235#define DUK_HOBJECT_CLASS_NUMBER 10
6236#define DUK_HOBJECT_CLASS_REGEXP 11
6237#define DUK_HOBJECT_CLASS_STRING 12
6238#define DUK_HOBJECT_CLASS_GLOBAL 13
6239#define DUK_HOBJECT_CLASS_SYMBOL 14
6240#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */
6241#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */
6242#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
6243#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
6244#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19
6245#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */
6246#define DUK_HOBJECT_CLASS_DATAVIEW 20
6247#define DUK_HOBJECT_CLASS_INT8ARRAY 21
6248#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
6249#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
6250#define DUK_HOBJECT_CLASS_INT16ARRAY 24
6251#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
6252#define DUK_HOBJECT_CLASS_INT32ARRAY 26
6253#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
6254#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
6255#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
6256#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29
6257#define DUK_HOBJECT_CLASS_MAX 29
6258
6259/* Class masks. */
6260#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
6261#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE)
6262#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
6263#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
6264#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
6265#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
6266#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
6267#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
6268#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
6269#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
6270#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
6271#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
6272#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
6273#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
6274#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
6275#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL)
6276#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
6277#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
6278#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
6279#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
6280#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
6281#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
6282#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
6283#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
6284#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
6285#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
6286#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
6287#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
6288#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
6289#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
6290
6291#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
6292 (DUK_HOBJECT_CMASK_ARRAYBUFFER | \
6293 DUK_HOBJECT_CMASK_DATAVIEW | \
6294 DUK_HOBJECT_CMASK_INT8ARRAY | \
6295 DUK_HOBJECT_CMASK_UINT8ARRAY | \
6296 DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
6297 DUK_HOBJECT_CMASK_INT16ARRAY | \
6298 DUK_HOBJECT_CMASK_UINT16ARRAY | \
6299 DUK_HOBJECT_CMASK_INT32ARRAY | \
6300 DUK_HOBJECT_CMASK_UINT32ARRAY | \
6301 DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
6302 DUK_HOBJECT_CMASK_FLOAT64ARRAY)
6303
6304#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
6305#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
6306#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
6307#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */
6308#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6309#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6310#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6311#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6312#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6313#else
6314#define DUK_HOBJECT_IS_BUFOBJ(h) 0
6315#endif
6316#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
6317#if defined(DUK_USE_ES6_PROXY)
6318#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
6319#else
6320#define DUK_HOBJECT_IS_PROXY(h) 0
6321#endif
6322
6323#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
6324 DUK_HOBJECT_FLAG_COMPFUNC | \
6325 DUK_HOBJECT_FLAG_NATFUNC)
6326
6327#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
6328 DUK_HOBJECT_FLAG_BOUNDFUNC | \
6329 DUK_HOBJECT_FLAG_COMPFUNC | \
6330 DUK_HOBJECT_FLAG_NATFUNC)
6331
6332#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h))
6333
6334/* Object has any exotic behavior(s). */
6335#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
6336 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
6337 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
6338 DUK_HOBJECT_FLAG_BUFOBJ | \
6339 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6340#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
6341
6342/* Object has any virtual properties (not counting Proxy behavior). */
6343#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
6344 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
6345 DUK_HOBJECT_FLAG_BUFOBJ)
6346#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
6347
6348#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6349#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6350#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6351#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6352#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6353#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6354#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6355#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6356#else
6357#define DUK_HOBJECT_HAS_BUFOBJ(h) 0
6358#endif
6359#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6360#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6361#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6362#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6363#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6364#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6365#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6366#define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6367#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6368#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6369#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6370#if defined(DUK_USE_ES6_PROXY)
6371#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6372#else
6373#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0
6374#endif
6375#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6376
6377#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6378#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6379#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6380#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6381#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6382#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6383#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6384#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6385#endif
6386#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6387#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6388#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6389#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6390#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6391#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6392#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6393#define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6394#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6395#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6396#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6397#if defined(DUK_USE_ES6_PROXY)
6398#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6399#endif
6400#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6401
6402#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6403#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6404#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6405#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6406#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6407#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6408#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6409#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6410#endif
6411#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6412#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6413#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6414#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6415#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6416#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6417#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6418#define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6419#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6420#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6421#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6422#if defined(DUK_USE_ES6_PROXY)
6423#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6424#endif
6425#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6426
6427/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
6428 * duk_hobject base header. This is used just for asserts so doesn't need to
6429 * be optimized.
6430 */
6431#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
6432 (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
6433 DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
6434 DUK_HOBJECT_IS_BOUNDFUNC((h)))
6435#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
6436
6437/* Flags used for property attributes in duk_propdesc and packed flags.
6438 * Must fit into 8 bits.
6439 */
6440#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */
6441#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */
6442#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */
6443#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */
6444#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored
6445 * (used by e.g. buffer virtual properties)
6446 */
6447#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
6448 DUK_PROPDESC_FLAG_ENUMERABLE | \
6449 DUK_PROPDESC_FLAG_CONFIGURABLE | \
6450 DUK_PROPDESC_FLAG_ACCESSOR)
6451
6452/* Additional flags which are passed in the same flags argument as property
6453 * flags but are not stored in object properties.
6454 */
6455#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */
6456
6457/* Convenience defines for property attributes. */
6458#define DUK_PROPDESC_FLAGS_NONE 0
6459#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
6460#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
6461#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
6462#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
6463#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
6464#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
6465#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
6466 DUK_PROPDESC_FLAG_ENUMERABLE | \
6467 DUK_PROPDESC_FLAG_CONFIGURABLE)
6468
6469/* Flags for duk_hobject_get_own_propdesc() and variants. */
6470#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */
6471#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */
6472
6473/*
6474 * Macro for object validity check
6475 *
6476 * Assert for currently guaranteed relations between flags, for instance.
6477 */
6478
6479#if defined(DUK_USE_ASSERTIONS)
6480DUK_INTERNAL_DECL void duk_hobject_assert_valid(duk_hobject *h);
6481#define DUK_HOBJECT_ASSERT_VALID(h) do { duk_hobject_assert_valid((h)); } while (0)
6482#else
6483#define DUK_HOBJECT_ASSERT_VALID(h) do {} while (0)
6484#endif
6485
6486/*
6487 * Macros to access the 'props' allocation.
6488 */
6489
6490#if defined(DUK_USE_HEAPPTR16)
6491#define DUK_HOBJECT_GET_PROPS(heap,h) \
6492 ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
6493#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
6494 ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
6495 } while (0)
6496#else
6497#define DUK_HOBJECT_GET_PROPS(heap,h) \
6498 ((h)->props)
6499#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
6500 (h)->props = (duk_uint8_t *) (x); \
6501 } while (0)
6502#endif
6503
6504#if defined(DUK_USE_HOBJECT_LAYOUT_1)
6505/* LAYOUT 1 */
6506#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6507 ((duk_hstring **) (void *) ( \
6508 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6509 ))
6510#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6511 ((duk_propvalue *) (void *) ( \
6512 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6513 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
6514 ))
6515#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6516 ((duk_uint8_t *) (void *) ( \
6517 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
6518 ))
6519#define DUK_HOBJECT_A_GET_BASE(heap,h) \
6520 ((duk_tval *) (void *) ( \
6521 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6522 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
6523 ))
6524#define DUK_HOBJECT_H_GET_BASE(heap,h) \
6525 ((duk_uint32_t *) (void *) ( \
6526 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6527 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6528 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6529 ))
6530#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6531 ( \
6532 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6533 (n_arr) * sizeof(duk_tval) + \
6534 (n_hash) * sizeof(duk_uint32_t) \
6535 )
6536#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 { \
6537 (set_e_k) = (duk_hstring **) (void *) (p_base); \
6538 (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
6539 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
6540 (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
6541 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
6542 } while (0)
6543#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
6544/* LAYOUT 2 */
6545#if (DUK_USE_ALIGN_BY == 4)
6546#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
6547#elif (DUK_USE_ALIGN_BY == 8)
6548#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
6549#elif (DUK_USE_ALIGN_BY == 1)
6550#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
6551#else
6552#error invalid DUK_USE_ALIGN_BY
6553#endif
6554#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6555 ((duk_hstring **) (void *) ( \
6556 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6557 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
6558 ))
6559#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6560 ((duk_propvalue *) (void *) ( \
6561 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6562 ))
6563#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6564 ((duk_uint8_t *) (void *) ( \
6565 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
6566 ))
6567#define DUK_HOBJECT_A_GET_BASE(heap,h) \
6568 ((duk_tval *) (void *) ( \
6569 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6570 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6571 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
6572 ))
6573#define DUK_HOBJECT_H_GET_BASE(heap,h) \
6574 ((duk_uint32_t *) (void *) ( \
6575 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6576 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6577 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
6578 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6579 ))
6580#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6581 ( \
6582 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6583 DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
6584 (n_arr) * sizeof(duk_tval) + \
6585 (n_hash) * sizeof(duk_uint32_t) \
6586 )
6587#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 { \
6588 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
6589 (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
6590 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
6591 (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
6592 sizeof(duk_uint8_t) * (n_ent) + \
6593 DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
6594 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
6595 } while (0)
6596#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
6597/* LAYOUT 3 */
6598#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6599 ((duk_hstring **) (void *) ( \
6600 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6601 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
6602 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6603 ))
6604#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6605 ((duk_propvalue *) (void *) ( \
6606 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6607 ))
6608#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6609 ((duk_uint8_t *) (void *) ( \
6610 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6611 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
6612 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
6613 DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
6614 ))
6615#define DUK_HOBJECT_A_GET_BASE(heap,h) \
6616 ((duk_tval *) (void *) ( \
6617 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6618 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
6619 ))
6620#define DUK_HOBJECT_H_GET_BASE(heap,h) \
6621 ((duk_uint32_t *) (void *) ( \
6622 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6623 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
6624 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6625 ))
6626#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6627 ( \
6628 (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
6629 (n_arr) * sizeof(duk_tval) + \
6630 (n_hash) * sizeof(duk_uint32_t) \
6631 )
6632#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 { \
6633 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
6634 (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
6635 (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
6636 (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
6637 (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
6638 } while (0)
6639#else
6640#error invalid hobject layout defines
6641#endif /* hobject property layout */
6642
6643#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
6644 DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
6645
6646#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
6647#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
6648#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
6649#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
6650#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
6651#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
6652#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
6653#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
6654#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
6655#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
6656#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
6657#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
6658#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
6659#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
6660#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
6661#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
6662
6663#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
6664 DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
6665 } while (0)
6666#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
6667 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
6668 } while (0)
6669#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
6670 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
6671 } while (0)
6672#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
6673 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
6674 } while (0)
6675#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
6676 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
6677 } while (0)
6678#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
6679 DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
6680 } while (0)
6681#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
6682 DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
6683 } while (0)
6684#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
6685 DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
6686#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
6687 DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
6688 } while (0)
6689
6690#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
6691 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
6692 } while (0)
6693
6694#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
6695 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
6696 } while (0)
6697
6698#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
6699#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
6700#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
6701#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
6702
6703#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
6704#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
6705#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
6706#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
6707
6708#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
6709#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
6710#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
6711#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
6712
6713#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
6714#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
6715#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
6716#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
6717
6718#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
6719#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
6720
6721/*
6722 * Macros for accessing size fields
6723 */
6724
6725#if defined(DUK_USE_OBJSIZES16)
6726#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
6727#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
6728#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
6729#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
6730#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
6731#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
6732#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
6733#if defined(DUK_USE_HOBJECT_HASH_PART)
6734#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
6735#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
6736#else
6737#define DUK_HOBJECT_GET_HSIZE(h) 0
6738#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
6739#endif
6740#else
6741#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
6742#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
6743#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
6744#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
6745#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
6746#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
6747#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
6748#if defined(DUK_USE_HOBJECT_HASH_PART)
6749#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
6750#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
6751#else
6752#define DUK_HOBJECT_GET_HSIZE(h) 0
6753#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
6754#endif
6755#endif
6756
6757/*
6758 * Misc
6759 */
6760
6761/* Maximum prototype traversal depth. Sanity limit which handles e.g.
6762 * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
6763 */
6764#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
6765
6766/*
6767 * ECMAScript [[Class]]
6768 */
6769
6770/* range check not necessary because all 4-bit values are mapped */
6771#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
6772
6773#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
6774 DUK_HEAP_GET_STRING( \
6775 (heap), \
6776 DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
6777 )
6778
6779/*
6780 * Macros for property handling
6781 */
6782
6783#if defined(DUK_USE_HEAPPTR16)
6784#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
6785 ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
6786#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
6787 (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
6788 } while (0)
6789#else
6790#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
6791 ((h)->prototype)
6792#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
6793 (h)->prototype = (x); \
6794 } while (0)
6795#endif
6796
6797/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
6798#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
6799
6800/* Set initial prototype, assume NULL previous prototype, INCREF new value,
6801 * tolerate NULL.
6802 */
6803#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
6804 duk_hthread *duk__thr = (thr); \
6805 duk_hobject *duk__obj = (h); \
6806 duk_hobject *duk__proto = (proto); \
6807 DUK_UNREF(duk__thr); \
6808 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
6809 DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
6810 DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
6811 } while (0)
6812
6813/*
6814 * Finalizer check
6815 */
6816
6817#if defined(DUK_USE_HEAPPTR16)
6818#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h))
6819#else
6820#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h))
6821#endif
6822
6823/*
6824 * Resizing and hash behavior
6825 */
6826
6827/* Sanity limit on max number of properties (allocated, not necessarily used).
6828 * This is somewhat arbitrary, but if we're close to 2**32 properties some
6829 * algorithms will fail (e.g. hash size selection, next prime selection).
6830 * Also, we use negative array/entry table indices to indicate 'not found',
6831 * so anything above 0x80000000 will cause trouble now.
6832 */
6833#if defined(DUK_USE_OBJSIZES16)
6834#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
6835#else
6836#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */
6837#endif
6838
6839/* internal align target for props allocation, must be 2*n for some n */
6840#if (DUK_USE_ALIGN_BY == 4)
6841#define DUK_HOBJECT_ALIGN_TARGET 4
6842#elif (DUK_USE_ALIGN_BY == 8)
6843#define DUK_HOBJECT_ALIGN_TARGET 8
6844#elif (DUK_USE_ALIGN_BY == 1)
6845#define DUK_HOBJECT_ALIGN_TARGET 1
6846#else
6847#error invalid DUK_USE_ALIGN_BY
6848#endif
6849
6850/*
6851 * PC-to-line constants
6852 */
6853
6854#define DUK_PC2LINE_SKIP 64
6855
6856/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
6857#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
6858
6859/*
6860 * Struct defs
6861 */
6862
6863struct duk_propaccessor {
6864 duk_hobject *get;
6865 duk_hobject *set;
6866};
6867
6868union duk_propvalue {
6869 /* The get/set pointers could be 16-bit pointer compressed but it
6870 * would make no difference on 32-bit platforms because duk_tval is
6871 * 8 bytes or more anyway.
6872 */
6873 duk_tval v;
6874 duk_propaccessor a;
6875};
6876
6877struct duk_propdesc {
6878 /* read-only values 'lifted' for ease of use */
6879 duk_small_uint_t flags;
6880 duk_hobject *get;
6881 duk_hobject *set;
6882
6883 /* for updating (all are set to < 0 for virtual properties) */
6884 duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
6885 duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
6886 duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
6887};
6888
6889struct duk_hobject {
6890 duk_heaphdr hdr;
6891
6892 /*
6893 * 'props' contains {key,value,flags} entries, optional array entries, and
6894 * an optional hash lookup table for non-array entries in a single 'sliced'
6895 * allocation. There are several layout options, which differ slightly in
6896 * generated code size/speed and alignment/padding; duk_features.h selects
6897 * the layout used.
6898 *
6899 * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
6900 *
6901 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
6902 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
6903 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
6904 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
6905 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
6906 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
6907 *
6908 * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
6909 *
6910 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
6911 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
6912 * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
6913 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
6914 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
6915 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
6916 *
6917 * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
6918 *
6919 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
6920 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
6921 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
6922 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
6923 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
6924 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
6925 *
6926 * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
6927 * requiring 4 or 8 byte alignment. This ensures proper alignment
6928 * for the entries, at the cost of memory footprint. However, it's
6929 * probably preferable to use another layout on such platforms instead.
6930 *
6931 * In layout 2, the key and value parts are swapped to avoid padding
6932 * the key array on platforms requiring alignment by 8. The flags part
6933 * is padded to get alignment for array entries. The 'e_next' count does
6934 * not need to be rounded as in layout 1.
6935 *
6936 * In layout 3, entry values and array values are always aligned properly,
6937 * and assuming pointers are at most 8 bytes, so are the entry keys. Hash
6938 * indices will be properly aligned (assuming pointers are at least 4 bytes).
6939 * Finally, flags don't need additional alignment. This layout provides
6940 * compact allocations without padding (even on platforms with alignment
6941 * requirements) at the cost of a bit slower lookups.
6942 *
6943 * Objects with few keys don't have a hash index; keys are looked up linearly,
6944 * which is cache efficient because the keys are consecutive. Larger objects
6945 * have a hash index part which contains integer indexes to the entries part.
6946 *
6947 * A single allocation reduces memory allocation overhead but requires more
6948 * work when any part needs to be resized. A sliced allocation for entries
6949 * makes linear key matching faster on most platforms (more locality) and
6950 * skimps on flags size (which would be followed by 3 bytes of padding in
6951 * most architectures if entries were placed in a struct).
6952 *
6953 * 'props' also contains internal properties distinguished with a non-BMP
6954 * prefix. Often used properties should be placed early in 'props' whenever
6955 * possible to make accessing them as fast a possible.
6956 */
6957
6958#if defined(DUK_USE_HEAPPTR16)
6959 /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
6960 * duk_hcompfunc) are not free to use h_extra16 for this reason.
6961 */
6962#else
6963 duk_uint8_t *props;
6964#endif
6965
6966 /* prototype: the only internal property lifted outside 'e' as it is so central */
6967#if defined(DUK_USE_HEAPPTR16)
6968 duk_uint16_t prototype16;
6969#else
6970 duk_hobject *prototype;
6971#endif
6972
6973#if defined(DUK_USE_OBJSIZES16)
6974 duk_uint16_t e_size16;
6975 duk_uint16_t e_next16;
6976 duk_uint16_t a_size16;
6977#if defined(DUK_USE_HOBJECT_HASH_PART)
6978 duk_uint16_t h_size16;
6979#endif
6980#else
6981 duk_uint32_t e_size; /* entry part size */
6982 duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
6983 duk_uint32_t a_size; /* array part size (entirely gc reachable) */
6984#if defined(DUK_USE_HOBJECT_HASH_PART)
6985 duk_uint32_t h_size; /* hash part size or 0 if unused */
6986#endif
6987#endif
6988};
6989
6990/*
6991 * Exposed data
6992 */
6993
6994#if !defined(DUK_SINGLE_FILE)
6995DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
6996#endif /* !DUK_SINGLE_FILE */
6997
6998/*
6999 * Prototypes
7000 */
7001
7002/* alloc and init */
7003DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
7004DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7005DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7006DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7007DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7008DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
7009#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
7010DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7011#endif
7012DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
7013DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7014DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7015DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7016DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
7017
7018/* resize */
7019DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
7020 duk_hobject *obj,
7021 duk_uint32_t new_e_size,
7022 duk_uint32_t new_a_size,
7023 duk_uint32_t new_h_size,
7024 duk_bool_t abandon_array);
7025DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
7026 duk_hobject *obj,
7027 duk_uint32_t new_e_size);
7028#if 0 /*unused*/
7029DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
7030 duk_hobject *obj,
7031 duk_uint32_t new_a_size);
7032#endif
7033
7034/* low-level property functions */
7035DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
7036DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
7037DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx);
7038DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs);
7039DUK_INTERNAL_DECL duk_tval *duk_hobject_find_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
7040DUK_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);
7041
7042/* core property functions */
7043DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
7044DUK_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);
7045DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
7046DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
7047
7048/* internal property functions */
7049#define DUK_DELPROP_FLAG_THROW (1U << 0)
7050#define DUK_DELPROP_FLAG_FORCE (1U << 1)
7051DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
7052DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
7053DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
7054DUK_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);
7055DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
7056#if defined(DUK_USE_HEAPPTR16)
7057DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj);
7058#else
7059DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj);
7060#endif
7061
7062/* helpers for defineProperty() and defineProperties() */
7063DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
7064 duk_idx_t idx_in,
7065 duk_uint_t *out_defprop_flags,
7066 duk_idx_t *out_idx_value,
7067 duk_hobject **out_getter,
7068 duk_hobject **out_setter);
7069DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
7070 duk_uint_t defprop_flags,
7071 duk_hobject *obj,
7072 duk_hstring *key,
7073 duk_idx_t idx_value,
7074 duk_hobject *get,
7075 duk_hobject *set,
7076 duk_bool_t throw_flag);
7077
7078/* Object built-in methods */
7079DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
7080DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
7081DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
7082DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
7083
7084/* internal properties */
7085DUK_INTERNAL_DECL duk_tval *duk_hobject_get_internal_value_tval_ptr(duk_heap *heap, duk_hobject *obj);
7086DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
7087DUK_INTERNAL_DECL duk_harray *duk_hobject_get_formals(duk_hthread *thr, duk_hobject *obj);
7088DUK_INTERNAL_DECL duk_hobject *duk_hobject_get_varmap(duk_hthread *thr, duk_hobject *obj);
7089
7090/* hobject management functions */
7091DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
7092
7093/* ES2015 proxy */
7094#if defined(DUK_USE_ES6_PROXY)
7095DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
7096DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
7097#endif
7098
7099/* enumeration */
7100DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
7101DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
7102DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
7103
7104/* macros */
7105DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
7106
7107/* pc2line */
7108#if defined(DUK_USE_PC2LINE)
7109DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
7110DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
7111#endif
7112
7113/* misc */
7114DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
7115
7116#if !defined(DUK_USE_OBJECT_BUILTIN)
7117/* These declarations are needed when related built-in is disabled and
7118 * genbuiltins.py won't automatically emit the declerations.
7119 */
7120DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
7121DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
7122#endif
7123
7124#endif /* DUK_HOBJECT_H_INCLUDED */
7125/* #include duk_hcompfunc.h */
7126#line 1 "duk_hcompfunc.h"
7127/*
7128 * Heap compiled function (ECMAScript function) representation.
7129 *
7130 * There is a single data buffer containing the ECMAScript function's
7131 * bytecode, constants, and inner functions.
7132 */
7133
7134#if !defined(DUK_HCOMPFUNC_H_INCLUDED)
7135#define DUK_HCOMPFUNC_H_INCLUDED
7136
7137/*
7138 * Field accessor macros
7139 */
7140
7141/* XXX: casts could be improved, especially for GET/SET DATA */
7142
7143#if defined(DUK_USE_HEAPPTR16)
7144#define DUK_HCOMPFUNC_GET_DATA(heap,h) \
7145 ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
7146#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
7147 (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7148 } while (0)
7149#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \
7150 ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
7151#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
7152 (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7153 } while (0)
7154#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \
7155 ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
7156#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
7157 (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7158 } while (0)
7159#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \
7160 ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
7161#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
7162 (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7163 } while (0)
7164#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \
7165 ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
7166#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
7167 (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7168 } while (0)
7169#else
7170#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data)
7171#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
7172 (h)->data = (duk_hbuffer *) (v); \
7173 } while (0)
7174#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs)
7175#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
7176 (h)->funcs = (v); \
7177 } while (0)
7178#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode)
7179#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
7180 (h)->bytecode = (v); \
7181 } while (0)
7182#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env)
7183#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
7184 (h)->lex_env = (v); \
7185 } while (0)
7186#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env)
7187#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
7188 (h)->var_env = (v); \
7189 } while (0)
7190#endif
7191
7192/*
7193 * Accessor macros for function specific data areas
7194 */
7195
7196/* Note: assumes 'data' is always a fixed buffer */
7197#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \
7198 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
7199
7200#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \
7201 ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
7202
7203#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \
7204 DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
7205
7206#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \
7207 DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
7208
7209#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \
7210 ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
7211
7212#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \
7213 ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
7214
7215/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
7216#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \
7217 ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
7218 DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
7219
7220#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \
7221 ( \
7222 (duk_size_t) \
7223 ( \
7224 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
7225 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
7226 ) \
7227 )
7228
7229#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \
7230 ( \
7231 (duk_size_t) \
7232 ( \
7233 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
7234 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
7235 ) \
7236 )
7237
7238#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \
7239 ( \
7240 (duk_size_t) \
7241 ( \
7242 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
7243 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
7244 ) \
7245 )
7246
7247#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \
7248 ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
7249
7250#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \
7251 ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
7252
7253#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
7254 ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
7255
7256/*
7257 * Validity assert
7258 */
7259
7260#if defined(DUK_USE_ASSERTIONS)
7261DUK_INTERNAL_DECL void duk_hcompfunc_assert_valid(duk_hcompfunc *h);
7262#define DUK_HCOMPFUNC_ASSERT_VALID(h) do { duk_hcompfunc_assert_valid((h)); } while (0)
7263#else
7264#define DUK_HCOMPFUNC_ASSERT_VALID(h) do {} while (0)
7265#endif
7266
7267/*
7268 * Main struct
7269 */
7270
7271struct duk_hcompfunc {
7272 /* shared object part */
7273 duk_hobject obj;
7274
7275 /*
7276 * Pointers to function data area for faster access. Function
7277 * data is a buffer shared between all closures of the same
7278 * "template" function. The data buffer is always fixed (non-
7279 * dynamic, hence stable), with a layout as follows:
7280 *
7281 * constants (duk_tval)
7282 * inner functions (duk_hobject *)
7283 * bytecode (duk_instr_t)
7284 *
7285 * Note: bytecode end address can be computed from 'data' buffer
7286 * size. It is not strictly necessary functionally, assuming
7287 * bytecode never jumps outside its allocated area. However,
7288 * it's a safety/robustness feature for avoiding the chance of
7289 * executing random data as bytecode due to a compiler error.
7290 *
7291 * Note: values in the data buffer must be incref'd (they will
7292 * be decref'd on release) for every compiledfunction referring
7293 * to the 'data' element.
7294 */
7295
7296 /* Data area, fixed allocation, stable data ptrs. */
7297#if defined(DUK_USE_HEAPPTR16)
7298 duk_uint16_t data16;
7299#else
7300 duk_hbuffer *data;
7301#endif
7302
7303 /* No need for constants pointer (= same as data).
7304 *
7305 * When using 16-bit packing alignment to 4 is nice. 'funcs' will be
7306 * 4-byte aligned because 'constants' are duk_tvals. For now the
7307 * inner function pointers are not compressed, so that 'bytecode' will
7308 * also be 4-byte aligned.
7309 */
7310#if defined(DUK_USE_HEAPPTR16)
7311 duk_uint16_t funcs16;
7312 duk_uint16_t bytecode16;
7313#else
7314 duk_hobject **funcs;
7315 duk_instr_t *bytecode;
7316#endif
7317
7318 /* Lexenv: lexical environment of closure, NULL for templates.
7319 * Varenv: variable environment of closure, NULL for templates.
7320 */
7321#if defined(DUK_USE_HEAPPTR16)
7322 duk_uint16_t lex_env16;
7323 duk_uint16_t var_env16;
7324#else
7325 duk_hobject *lex_env;
7326 duk_hobject *var_env;
7327#endif
7328
7329 /*
7330 * 'nregs' registers are allocated on function entry, at most 'nargs'
7331 * are initialized to arguments, and the rest to undefined. Arguments
7332 * above 'nregs' are not mapped to registers. All registers in the
7333 * active stack range must be initialized because they are GC reachable.
7334 * 'nargs' is needed so that if the function is given more than 'nargs'
7335 * arguments, the additional arguments do not 'clobber' registers
7336 * beyond 'nregs' which must be consistently initialized to undefined.
7337 *
7338 * Usually there is no need to know which registers are mapped to
7339 * local variables. Registers may be allocated to variable in any
7340 * way (even including gaps). However, a register-variable mapping
7341 * must be the same for the duration of the function execution and
7342 * the register cannot be used for anything else.
7343 *
7344 * When looking up variables by name, the '_Varmap' map is used.
7345 * When an activation closes, registers mapped to arguments are
7346 * copied into the environment record based on the same map. The
7347 * reverse map (from register to variable) is not currently needed
7348 * at run time, except for debugging, so it is not maintained.
7349 */
7350
7351 duk_uint16_t nregs; /* regs to allocate */
7352 duk_uint16_t nargs; /* number of arguments allocated to regs */
7353
7354 /*
7355 * Additional control information is placed into the object itself
7356 * as internal properties to avoid unnecessary fields for the
7357 * majority of functions. The compiler tries to omit internal
7358 * control fields when possible.
7359 *
7360 * Function templates:
7361 *
7362 * {
7363 * name: "func", // declaration, named function expressions
7364 * fileName: <debug info for creating nice errors>
7365 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
7366 * _Formals: [ "arg1", "arg2" ],
7367 * _Source: "function func(arg1, arg2) { ... }",
7368 * _Pc2line: <debug info for pc-to-line mapping>,
7369 * }
7370 *
7371 * Function instances:
7372 *
7373 * {
7374 * length: 2,
7375 * prototype: { constructor: <func> },
7376 * caller: <thrower>,
7377 * arguments: <thrower>,
7378 * name: "func", // declaration, named function expressions
7379 * fileName: <debug info for creating nice errors>
7380 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
7381 * _Formals: [ "arg1", "arg2" ],
7382 * _Source: "function func(arg1, arg2) { ... }",
7383 * _Pc2line: <debug info for pc-to-line mapping>,
7384 * }
7385 *
7386 * More detailed description of these properties can be found
7387 * in the documentation.
7388 */
7389
7390#if defined(DUK_USE_DEBUGGER_SUPPORT)
7391 /* Line number range for function. Needed during debugging to
7392 * determine active breakpoints.
7393 */
7394 duk_uint32_t start_line;
7395 duk_uint32_t end_line;
7396#endif
7397};
7398
7399#endif /* DUK_HCOMPFUNC_H_INCLUDED */
7400/* #include duk_hnatfunc.h */
7401#line 1 "duk_hnatfunc.h"
7402/*
7403 * Heap native function representation.
7404 */
7405
7406#if !defined(DUK_HNATFUNC_H_INCLUDED)
7407#define DUK_HNATFUNC_H_INCLUDED
7408
7409#if defined(DUK_USE_ASSERTIONS)
7410DUK_INTERNAL_DECL void duk_hnatfunc_assert_valid(duk_hnatfunc *h);
7411#define DUK_HNATFUNC_ASSERT_VALID(h) do { duk_hnatfunc_assert_valid((h)); } while (0)
7412#else
7413#define DUK_HNATFUNC_ASSERT_VALID(h) do {} while (0)
7414#endif
7415
7416#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1)
7417#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff)
7418
7419struct duk_hnatfunc {
7420 /* shared object part */
7421 duk_hobject obj;
7422
7423 duk_c_function func;
7424 duk_int16_t nargs;
7425 duk_int16_t magic;
7426
7427 /* The 'magic' field allows an opaque 16-bit field to be accessed by the
7428 * Duktape/C function. This allows, for instance, the same native function
7429 * to be used for a set of very similar functions, with the 'magic' field
7430 * providing the necessary non-argument flags / values to guide the behavior
7431 * of the native function. The value is signed on purpose: it is easier to
7432 * convert a signed value to unsigned (simply AND with 0xffff) than vice
7433 * versa.
7434 *
7435 * Note: cannot place nargs/magic into the heaphdr flags, because
7436 * duk_hobject takes almost all flags already.
7437 */
7438};
7439
7440#endif /* DUK_HNATFUNC_H_INCLUDED */
7441/* #include duk_hboundfunc.h */
7442#line 1 "duk_hboundfunc.h"
7443/*
7444 * Bound function representation.
7445 */
7446
7447#if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
7448#define DUK_HBOUNDFUNC_H_INCLUDED
7449
7450/* Artificial limit for args length. Ensures arithmetic won't overflow
7451 * 32 bits when combining bound functions.
7452 */
7453#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
7454
7455#if defined(DUK_USE_ASSERTIONS)
7456DUK_INTERNAL_DECL void duk_hboundfunc_assert_valid(duk_hboundfunc *h);
7457#define DUK_HBOUNDFUNC_ASSERT_VALID(h) do { duk_hboundfunc_assert_valid((h)); } while (0)
7458#else
7459#define DUK_HBOUNDFUNC_ASSERT_VALID(h) do {} while (0)
7460#endif
7461
7462struct duk_hboundfunc {
7463 /* Shared object part. */
7464 duk_hobject obj;
7465
7466 /* Final target function, stored as duk_tval so that lightfunc can be
7467 * represented too.
7468 */
7469 duk_tval target;
7470
7471 /* This binding. */
7472 duk_tval this_binding;
7473
7474 /* Arguments to prepend. */
7475 duk_tval *args; /* Separate allocation. */
7476 duk_idx_t nargs;
7477};
7478
7479#endif /* DUK_HBOUNDFUNC_H_INCLUDED */
7480/* #include duk_hbufobj.h */
7481#line 1 "duk_hbufobj.h"
7482/*
7483 * Heap Buffer object representation. Used for all Buffer variants.
7484 */
7485
7486#if !defined(DUK_HBUFOBJ_H_INCLUDED)
7487#define DUK_HBUFOBJ_H_INCLUDED
7488
7489#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
7490
7491/* All element accessors are host endian now (driven by TypedArray spec). */
7492#define DUK_HBUFOBJ_ELEM_UINT8 0
7493#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1
7494#define DUK_HBUFOBJ_ELEM_INT8 2
7495#define DUK_HBUFOBJ_ELEM_UINT16 3
7496#define DUK_HBUFOBJ_ELEM_INT16 4
7497#define DUK_HBUFOBJ_ELEM_UINT32 5
7498#define DUK_HBUFOBJ_ELEM_INT32 6
7499#define DUK_HBUFOBJ_ELEM_FLOAT32 7
7500#define DUK_HBUFOBJ_ELEM_FLOAT64 8
7501#define DUK_HBUFOBJ_ELEM_MAX 8
7502
7503#if defined(DUK_USE_ASSERTIONS)
7504DUK_INTERNAL_DECL void duk_hbufobj_assert_valid(duk_hbufobj *h);
7505#define DUK_HBUFOBJ_ASSERT_VALID(h) do { duk_hbufobj_assert_valid((h)); } while (0)
7506#else
7507#define DUK_HBUFOBJ_ASSERT_VALID(h) do {} while (0)
7508#endif
7509
7510/* Get the current data pointer (caller must ensure buf != NULL) as a
7511 * duk_uint8_t ptr. Note that the result may be NULL if the underlying
7512 * buffer has zero size and is not a fixed buffer.
7513 */
7514#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
7515 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7516 (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
7517
7518/* True if slice is full, i.e. offset is zero and length covers the entire
7519 * buffer. This status may change independently of the duk_hbufobj if
7520 * the underlying buffer is dynamic and changes without the hbufobj
7521 * being changed.
7522 */
7523#define DUK_HBUFOBJ_FULL_SLICE(h) \
7524 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7525 ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
7526
7527/* Validate that the whole slice [0,length[ is contained in the underlying
7528 * buffer. Caller must ensure 'buf' != NULL.
7529 */
7530#define DUK_HBUFOBJ_VALID_SLICE(h) \
7531 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7532 ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
7533
7534/* Validate byte read/write for virtual 'offset', i.e. check that the
7535 * offset, taking into account h->offset, is within the underlying
7536 * buffer size. This is a safety check which is needed to ensure
7537 * that even a misconfigured duk_hbufobj never causes memory unsafe
7538 * behavior (e.g. if an underlying dynamic buffer changes after being
7539 * setup). Caller must ensure 'buf' != NULL.
7540 */
7541#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
7542 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7543 ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
7544
7545#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
7546 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7547 ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
7548
7549/* Clamp an input byte length (already assumed to be within the nominal
7550 * duk_hbufobj 'length') to the current dynamic buffer limits to yield
7551 * a byte length limit that's safe for memory accesses. This value can
7552 * be invalidated by any side effect because it may trigger a user
7553 * callback that resizes the underlying buffer.
7554 */
7555#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
7556 (DUK_ASSERT_EXPR((h) != NULL), \
7557 duk_hbufobj_clamp_bytelength((h), (len)))
7558
7559/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
7560#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray)
7561
7562struct duk_hbufobj {
7563 /* Shared object part. */
7564 duk_hobject obj;
7565
7566 /* Underlying buffer (refcounted), may be NULL. */
7567 duk_hbuffer *buf;
7568
7569 /* .buffer reference to an ArrayBuffer, may be NULL. */
7570 duk_hobject *buf_prop;
7571
7572 /* Slice and accessor information.
7573 *
7574 * Because the underlying buffer may be dynamic, these may be
7575 * invalidated by the buffer being modified so that both offset
7576 * and length should be validated before every access. Behavior
7577 * when the underlying buffer has changed doesn't need to be clean:
7578 * virtual 'length' doesn't need to be affected, reads can return
7579 * zero/NaN, and writes can be ignored.
7580 *
7581 * Note that a data pointer cannot be precomputed because 'buf' may
7582 * be dynamic and its pointer unstable.
7583 */
7584
7585 duk_uint_t offset; /* byte offset to buf */
7586 duk_uint_t length; /* byte index limit for element access, exclusive */
7587 duk_uint8_t shift; /* element size shift:
7588 * 0 = u8/i8
7589 * 1 = u16/i16
7590 * 2 = u32/i32/float
7591 * 3 = double
7592 */
7593 duk_uint8_t elem_type; /* element type */
7594 duk_uint8_t is_typedarray;
7595};
7596
7597DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
7598DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
7599DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
7600DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
7601DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
7602
7603#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
7604
7605/* nothing */
7606
7607#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
7608#endif /* DUK_HBUFOBJ_H_INCLUDED */
7609/* #include duk_hthread.h */
7610#line 1 "duk_hthread.h"
7611/*
7612 * Heap thread object representation.
7613 *
7614 * duk_hthread is also the 'context' for public API functions via a
7615 * different typedef. Most API calls operate on the topmost frame
7616 * of the value stack only.
7617 */
7618
7619#if !defined(DUK_HTHREAD_H_INCLUDED)
7620#define DUK_HTHREAD_H_INCLUDED
7621
7622/*
7623 * Stack constants
7624 */
7625
7626/* Initial valstack size, roughly 0.7kiB. */
7627#define DUK_VALSTACK_INITIAL_SIZE 96U
7628
7629/* Internal extra elements assumed on function entry, always added to
7630 * user-defined 'extra' for e.g. the duk_check_stack() call.
7631 */
7632#define DUK_VALSTACK_INTERNAL_EXTRA 32U
7633
7634/* Number of elements guaranteed to be user accessible (in addition to call
7635 * arguments) on Duktape/C function entry. This is the major public API
7636 * commitment.
7637 */
7638#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
7639
7640/*
7641 * Activation defines
7642 */
7643
7644#define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */
7645#define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */
7646#define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */
7647#define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */
7648#define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */
7649#define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */
7650#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */
7651
7652#define DUK_ACT_GET_FUNC(act) ((act)->func)
7653
7654/*
7655 * Flags for __FILE__ / __LINE__ registered into tracedata
7656 */
7657
7658#define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
7659
7660/*
7661 * Catcher defines
7662 */
7663
7664/* XXX: remove catcher type entirely */
7665
7666/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
7667#define DUK_CAT_TYPE_MASK 0x0000000fUL
7668#define DUK_CAT_TYPE_BITS 4
7669#define DUK_CAT_LABEL_MASK 0xffffff00UL
7670#define DUK_CAT_LABEL_BITS 24
7671#define DUK_CAT_LABEL_SHIFT 8
7672
7673#define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */
7674#define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */
7675#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */
7676#define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */
7677
7678#define DUK_CAT_TYPE_UNKNOWN 0
7679#define DUK_CAT_TYPE_TCF 1
7680#define DUK_CAT_TYPE_LABEL 2
7681
7682#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK)
7683#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
7684
7685#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
7686#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
7687#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
7688#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
7689
7690#define DUK_CAT_SET_CATCH_ENABLED(c) do { \
7691 (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
7692 } while (0)
7693#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \
7694 (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
7695 } while (0)
7696#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \
7697 (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
7698 } while (0)
7699#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \
7700 (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
7701 } while (0)
7702
7703#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \
7704 (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
7705 } while (0)
7706#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \
7707 (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
7708 } while (0)
7709#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \
7710 (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
7711 } while (0)
7712#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \
7713 (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
7714 } while (0)
7715
7716/*
7717 * Thread defines
7718 */
7719
7720#if defined(DUK_USE_ROM_STRINGS)
7721#define DUK_HTHREAD_GET_STRING(thr,idx) \
7722 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
7723#else /* DUK_USE_ROM_STRINGS */
7724#if defined(DUK_USE_HEAPPTR16)
7725#define DUK_HTHREAD_GET_STRING(thr,idx) \
7726 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
7727#else
7728#define DUK_HTHREAD_GET_STRING(thr,idx) \
7729 ((thr)->strs[(idx)])
7730#endif
7731#endif /* DUK_USE_ROM_STRINGS */
7732
7733/* values for the state field */
7734#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
7735#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
7736#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */
7737#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */
7738#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */
7739
7740/* Executor interrupt default interval when nothing else requires a
7741 * smaller value. The default interval must be small enough to allow
7742 * for reasonable execution timeout checking but large enough to keep
7743 * impact on execution performance low.
7744 */
7745#if defined(DUK_USE_INTERRUPT_COUNTER)
7746#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L)
7747#endif
7748
7749/*
7750 * Assert context is valid: non-NULL pointer, fields look sane.
7751 *
7752 * This is used by public API call entrypoints to catch invalid 'ctx' pointers
7753 * as early as possible; invalid 'ctx' pointers cause very odd and difficult to
7754 * diagnose behavior so it's worth checking even when the check is not 100%.
7755 */
7756
7757#if defined(DUK_USE_ASSERTIONS)
7758/* Assertions for internals. */
7759DUK_INTERNAL_DECL void duk_hthread_assert_valid(duk_hthread *thr);
7760#define DUK_HTHREAD_ASSERT_VALID(thr) do { duk_hthread_assert_valid((thr)); } while (0)
7761
7762/* Assertions for public API calls; a bit stronger. */
7763DUK_INTERNAL_DECL void duk_ctx_assert_valid(duk_hthread *thr);
7764#define DUK_CTX_ASSERT_VALID(thr) do { duk_ctx_assert_valid((thr)); } while (0)
7765#else
7766#define DUK_HTHREAD_ASSERT_VALID(thr) do {} while (0)
7767#define DUK_CTX_ASSERT_VALID(thr) do {} while (0)
7768#endif
7769
7770/* Assertions for API call entry specifically. Checks 'ctx' but also may
7771 * check internal state (e.g. not in a debugger transport callback).
7772 */
7773#define DUK_ASSERT_API_ENTRY(thr) do { \
7774 DUK_CTX_ASSERT_VALID((thr)); \
7775 DUK_ASSERT((thr)->heap != NULL); \
7776 DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \
7777 } while (0)
7778
7779/*
7780 * Assertion helpers.
7781 */
7782
7783#define DUK_ASSERT_STRIDX_VALID(val) \
7784 DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS)
7785
7786#define DUK_ASSERT_BIDX_VALID(val) \
7787 DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS)
7788
7789/*
7790 * Misc
7791 */
7792
7793/* Fast access to 'this' binding. Assumes there's a call in progress. */
7794#define DUK_HTHREAD_THIS_PTR(thr) \
7795 (DUK_ASSERT_EXPR((thr) != NULL), \
7796 DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
7797 (thr)->valstack_bottom - 1)
7798
7799/*
7800 * Struct defines
7801 */
7802
7803/* Fields are ordered for alignment/packing. */
7804struct duk_activation {
7805 duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
7806 duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
7807 duk_activation *parent; /* previous (parent) activation (or NULL if none) */
7808 duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
7809 duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
7810 duk_catcher *cat; /* current catcher (or NULL) */
7811
7812#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7813 /* Previous value of 'func' caller, restored when unwound. Only in use
7814 * when 'func' is non-strict.
7815 */
7816 duk_hobject *prev_caller;
7817#endif
7818
7819 duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
7820
7821 /* bottom_byteoff and retval_byteoff are only used for book-keeping
7822 * of ECMAScript-initiated calls, to allow returning to an ECMAScript
7823 * function properly.
7824 */
7825
7826 /* Bottom of valstack for this activation, used to reset
7827 * valstack_bottom on return; offset is absolute. There's
7828 * no need to track 'top' because native call handling deals
7829 * with that using locals, and for ECMAScript returns 'nregs'
7830 * indicates the necessary top.
7831 */
7832 duk_size_t bottom_byteoff;
7833
7834 /* Return value when returning to this activation (points to caller
7835 * reg, not callee reg); offset is absolute (only set if activation is
7836 * not topmost).
7837 *
7838 * Note: bottom_byteoff is always set, while retval_byteoff is only
7839 * applicable for activations below the topmost one. Currently
7840 * retval_byteoff for the topmost activation is considered garbage
7841 * (and it not initialized on entry or cleared on return; may contain
7842 * previous or garbage values).
7843 */
7844 duk_size_t retval_byteoff;
7845
7846 /* Current 'this' binding is the value just below bottom.
7847 * Previously, 'this' binding was handled with an index to the
7848 * (calling) valstack. This works for everything except tail
7849 * calls, which must not "accumulate" valstack temps.
7850 */
7851
7852 /* Value stack reserve (valstack_end) byte offset to be restored
7853 * when returning to this activation. Only used by the bytecode
7854 * executor.
7855 */
7856 duk_size_t reserve_byteoff;
7857
7858#if defined(DUK_USE_DEBUGGER_SUPPORT)
7859 duk_uint32_t prev_line; /* needed for stepping */
7860#endif
7861
7862 duk_small_uint_t flags;
7863};
7864
7865struct duk_catcher {
7866 duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */
7867 duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
7868 /* (reference is valid as long activation exists) */
7869 duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
7870 duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
7871 duk_uint32_t flags; /* type and control flags, label number */
7872 /* XXX: could pack 'flags' and 'idx_base' to same value in practice,
7873 * on 32-bit targets this would make duk_catcher 16 bytes.
7874 */
7875};
7876
7877struct duk_hthread {
7878 /* Shared object part */
7879 duk_hobject obj;
7880
7881 /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy
7882 * the current PC back into the topmost activation when activation
7883 * state is about to change (or "syncing" is otherwise needed). This
7884 * is rather awkward but important for performance, see execution.rst.
7885 */
7886 duk_instr_t **ptr_curr_pc;
7887
7888 /* Backpointers. */
7889 duk_heap *heap;
7890
7891 /* Current strictness flag: affects API calls. */
7892 duk_uint8_t strict;
7893
7894 /* Thread state. */
7895 duk_uint8_t state;
7896 duk_uint8_t unused1;
7897 duk_uint8_t unused2;
7898
7899 /* XXX: Valstack and callstack are currently assumed to have non-NULL
7900 * pointers. Relaxing this would not lead to big benefits (except
7901 * perhaps for terminated threads).
7902 */
7903
7904 /* Value stack: these are expressed as pointers for faster stack
7905 * manipulation. [valstack,valstack_top[ is GC-reachable,
7906 * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept
7907 * initialized as 'undefined'. [valstack,valstack_end[ is the
7908 * guaranteed/reserved space and the valstack cannot be resized to
7909 * a smaller size. [valstack_end,valstack_alloc_end[ is currently
7910 * allocated slack that can be used to grow the current guaranteed
7911 * space but may be shrunk away without notice.
7912 *
7913 *
7914 * <----------------------- guaranteed --->
7915 * <---- slack --->
7916 * <--- frame --->
7917 * .-------------+=============+----------+--------------.
7918 * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu|
7919 * `-------------+=============+----------+--------------'
7920 *
7921 * ^ ^ ^ ^ ^
7922 * | | | | |
7923 * valstack bottom top end alloc_end
7924 *
7925 * xxx = arbitrary values, below current frame
7926 * yyy = arbitrary values, inside current frame
7927 * uuu = outside active value stack, initialized to 'undefined'
7928 */
7929 duk_tval *valstack; /* start of valstack allocation */
7930 duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */
7931 duk_tval *valstack_alloc_end; /* end of valstack allocation */
7932 duk_tval *valstack_bottom; /* bottom of current frame */
7933 duk_tval *valstack_top; /* top of current frame (exclusive) */
7934
7935 /* Call stack, represented as a linked list starting from the current
7936 * activation (or NULL if nothing is active).
7937 */
7938 duk_activation *callstack_curr; /* current activation (or NULL if none) */
7939 duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */
7940 duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
7941
7942 /* Yield/resume book-keeping. */
7943 duk_hthread *resumer; /* who resumed us (if any) */
7944
7945 /* Current compiler state (if any), used for augmenting SyntaxErrors. */
7946 duk_compiler_ctx *compile_ctx;
7947
7948#if defined(DUK_USE_INTERRUPT_COUNTER)
7949 /* Interrupt counter for triggering a slow path check for execution
7950 * timeout, debugger interaction such as breakpoints, etc. The value
7951 * is valid for the current running thread, and both the init and
7952 * counter values are copied whenever a thread switch occurs. It's
7953 * important for the counter to be conveniently accessible for the
7954 * bytecode executor inner loop for performance reasons.
7955 */
7956 duk_int_t interrupt_counter; /* countdown state */
7957 duk_int_t interrupt_init; /* start value for current countdown */
7958#endif
7959
7960 /* Builtin-objects; may or may not be shared with other threads,
7961 * threads existing in different "compartments" will have different
7962 * built-ins. Must be stored on a per-thread basis because there
7963 * is no intermediate structure for a thread group / compartment.
7964 * This takes quite a lot of space, currently 43x4 = 172 bytes on
7965 * 32-bit platforms.
7966 *
7967 * In some cases the builtins array could be ROM based, but it's
7968 * sometimes edited (e.g. for sandboxing) so it's better to keep
7969 * this array in RAM.
7970 */
7971 duk_hobject *builtins[DUK_NUM_BUILTINS];
7972
7973 /* Convenience copies from heap/vm for faster access. */
7974#if defined(DUK_USE_ROM_STRINGS)
7975 /* No field needed when strings are in ROM. */
7976#else
7977#if defined(DUK_USE_HEAPPTR16)
7978 duk_uint16_t *strs16;
7979#else
7980 duk_hstring **strs;
7981#endif
7982#endif
7983};
7984
7985/*
7986 * Prototypes
7987 */
7988
7989DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
7990DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
7991DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
7992DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
7993
7994DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr);
7995DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act);
7996DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr);
7997DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr);
7998DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level);
7999
8000DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr);
8001DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat);
8002DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act);
8003DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act);
8004
8005#if defined(DUK_USE_FINALIZER_TORTURE)
8006DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr);
8007#endif
8008
8009DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
8010
8011#if defined(DUK_USE_DEBUGGER_SUPPORT)
8012DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
8013#endif
8014DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
8015DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
8016DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
8017
8018#endif /* DUK_HTHREAD_H_INCLUDED */
8019/* #include duk_harray.h */
8020#line 1 "duk_harray.h"
8021/*
8022 * Array object representation, used for actual Array instances.
8023 *
8024 * All objects with the exotic array behavior (which must coincide with having
8025 * internal class array) MUST be duk_harrays. No other object can be a
8026 * duk_harray. However, duk_harrays may not always have an array part.
8027 */
8028
8029#if !defined(DUK_HARRAY_H_INCLUDED)
8030#define DUK_HARRAY_H_INCLUDED
8031
8032#if defined(DUK_USE_ASSERTIONS)
8033DUK_INTERNAL_DECL void duk_harray_assert_valid(duk_harray *h);
8034#define DUK_HARRAY_ASSERT_VALID(h) do { duk_harray_assert_valid((h)); } while (0)
8035#else
8036#define DUK_HARRAY_ASSERT_VALID(h) do {} while (0)
8037#endif
8038
8039#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable)
8040#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable)
8041#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0)
8042#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0)
8043
8044struct duk_harray {
8045 /* Shared object part. */
8046 duk_hobject obj;
8047
8048 /* Array .length.
8049 *
8050 * At present Array .length may be smaller, equal, or even larger
8051 * than the allocated underlying array part. Fast path code must
8052 * always take this into account carefully.
8053 */
8054 duk_uint32_t length;
8055
8056 /* Array .length property attributes. The property is always
8057 * non-enumerable and non-configurable. It's initially writable
8058 * but per Object.defineProperty() rules it can be made non-writable
8059 * even if it is non-configurable. Thus we need to track the
8060 * writability explicitly.
8061 *
8062 * XXX: this field to be eliminated and moved into duk_hobject
8063 * flags field to save space.
8064 */
8065 duk_bool_t length_nonwritable;
8066};
8067
8068#endif /* DUK_HARRAY_H_INCLUDED */
8069/* #include duk_henv.h */
8070#line 1 "duk_henv.h"
8071/*
8072 * Environment object representation.
8073 */
8074
8075#if !defined(DUK_HENV_H_INCLUDED)
8076#define DUK_HENV_H_INCLUDED
8077
8078#if defined(DUK_USE_ASSERTIONS)
8079DUK_INTERNAL_DECL void duk_hdecenv_assert_valid(duk_hdecenv *h);
8080DUK_INTERNAL_DECL void duk_hobjenv_assert_valid(duk_hobjenv *h);
8081#define DUK_HDECENV_ASSERT_VALID(h) do { duk_hdecenv_assert_valid((h)); } while (0)
8082#define DUK_HOBJENV_ASSERT_VALID(h) do { duk_hobjenv_assert_valid((h)); } while (0)
8083#else
8084#define DUK_HDECENV_ASSERT_VALID(h) do {} while (0)
8085#define DUK_HOBJENV_ASSERT_VALID(h) do {} while (0)
8086#endif
8087
8088struct duk_hdecenv {
8089 /* Shared object part. */
8090 duk_hobject obj;
8091
8092 /* These control variables provide enough information to access live
8093 * variables for a closure that is still open. If thread == NULL,
8094 * the record is closed and the identifiers are in the property table.
8095 */
8096 duk_hthread *thread;
8097 duk_hobject *varmap;
8098 duk_size_t regbase_byteoff;
8099};
8100
8101struct duk_hobjenv {
8102 /* Shared object part. */
8103 duk_hobject obj;
8104
8105 /* Target object and 'this' binding for object binding. */
8106 duk_hobject *target;
8107
8108 /* The 'target' object is used as a this binding in only some object
8109 * environments. For example, the global environment does not provide
8110 * a this binding, but a with statement does.
8111 */
8112 duk_bool_t has_this;
8113};
8114
8115#endif /* DUK_HENV_H_INCLUDED */
8116/* #include duk_hbuffer.h */
8117#line 1 "duk_hbuffer.h"
8118/*
8119 * Heap buffer representation.
8120 *
8121 * Heap allocated user data buffer which is either:
8122 *
8123 * 1. A fixed size buffer (data follows header statically)
8124 * 2. A dynamic size buffer (data pointer follows header)
8125 *
8126 * The data pointer for a variable size buffer of zero size may be NULL.
8127 */
8128
8129#if !defined(DUK_HBUFFER_H_INCLUDED)
8130#define DUK_HBUFFER_H_INCLUDED
8131
8132/*
8133 * Flags
8134 *
8135 * Fixed buffer: 0
8136 * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
8137 * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
8138 */
8139
8140#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
8141#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
8142
8143#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8144#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8145
8146#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8147#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8148
8149#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8150#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8151
8152/*
8153 * Misc defines
8154 */
8155
8156/* Impose a maximum buffer length for now. Restricted artificially to
8157 * ensure resize computations or adding a heap header length won't
8158 * overflow size_t and that a signed duk_int_t can hold a buffer
8159 * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
8160 */
8161
8162#if defined(DUK_USE_BUFLEN16)
8163#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
8164#else
8165/* Intentionally not 0x7fffffffUL; at least JSON code expects that
8166 * 2*len + 2 fits in 32 bits.
8167 */
8168#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
8169#endif
8170
8171/*
8172 * Field access
8173 */
8174
8175#if defined(DUK_USE_BUFLEN16)
8176/* size stored in duk_heaphdr unused flag bits */
8177#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
8178#define DUK_HBUFFER_SET_SIZE(x,v) do { \
8179 duk_size_t duk__v; \
8180 duk__v = (v); \
8181 DUK_ASSERT(duk__v <= 0xffffUL); \
8182 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
8183 } while (0)
8184#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
8185 (x)->hdr.h_flags += ((dv) << 16); \
8186 } while (0)
8187#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
8188 (x)->hdr.h_flags -= ((dv) << 16); \
8189 } while (0)
8190#else
8191#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
8192#define DUK_HBUFFER_SET_SIZE(x,v) do { \
8193 ((duk_hbuffer *) (x))->size = (v); \
8194 } while (0)
8195#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
8196 (x)->size += (dv); \
8197 } while (0)
8198#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
8199 (x)->size -= (dv); \
8200 } while (0)
8201#endif
8202
8203#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8204#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
8205
8206#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8207#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
8208#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
8209#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
8210
8211#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8212#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
8213
8214#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1))
8215
8216#if defined(DUK_USE_HEAPPTR16)
8217#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
8218 ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
8219#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
8220 ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
8221 } while (0)
8222#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
8223 ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
8224 } while (0)
8225#else
8226#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
8227#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
8228 (x)->curr_alloc = (void *) (v); \
8229 } while (0)
8230#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
8231 (x)->curr_alloc = (void *) NULL; \
8232 } while (0)
8233#endif
8234
8235/* No pointer compression because pointer is potentially outside of
8236 * Duktape heap.
8237 */
8238#if defined(DUK_USE_HEAPPTR16)
8239#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
8240 ((void *) (x)->curr_alloc)
8241#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
8242 (x)->curr_alloc = (void *) (v); \
8243 } while (0)
8244#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
8245 (x)->curr_alloc = (void *) NULL; \
8246 } while (0)
8247#else
8248#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
8249 ((void *) (x)->curr_alloc)
8250#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
8251 (x)->curr_alloc = (void *) (v); \
8252 } while (0)
8253#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
8254 (x)->curr_alloc = (void *) NULL; \
8255 } while (0)
8256#endif
8257
8258/* Get a pointer to the current buffer contents (matching current allocation
8259 * size). May be NULL for zero size dynamic/external buffer.
8260 */
8261#if defined(DUK_USE_HEAPPTR16)
8262#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
8263 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
8264 ( \
8265 DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
8266 DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
8267 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
8268 ) : \
8269 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
8270 )
8271#else
8272/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
8273 * have the same layout so checking for fixed vs. dynamic (or external) is enough.
8274 */
8275#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
8276 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
8277 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
8278 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
8279 )
8280#endif
8281
8282/* Validity assert. */
8283#if defined(DUK_USE_ASSERTIONS)
8284DUK_INTERNAL_DECL void duk_hbuffer_assert_valid(duk_hbuffer *h);
8285#define DUK_HBUFFER_ASSERT_VALID(h) do { duk_hbuffer_assert_valid((h)); } while (0)
8286#else
8287#define DUK_HBUFFER_ASSERT_VALID(h) do {} while (0)
8288#endif
8289
8290/*
8291 * Structs
8292 */
8293
8294/* Shared prefix for all buffer types. */
8295struct duk_hbuffer {
8296 duk_heaphdr hdr;
8297
8298 /* It's not strictly necessary to track the current size, but
8299 * it is useful for writing robust native code.
8300 */
8301
8302 /* Current size. */
8303#if defined(DUK_USE_BUFLEN16)
8304 /* Stored in duk_heaphdr unused flags. */
8305#else
8306 duk_size_t size;
8307#endif
8308
8309 /*
8310 * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
8311 * flag.
8312 *
8313 * If the flag is clear (the buffer is a fixed size one), the buffer
8314 * data follows the header directly, consisting of 'size' bytes.
8315 *
8316 * If the flag is set, the actual buffer is allocated separately, and
8317 * a few control fields follow the header. Specifically:
8318 *
8319 * - a "void *" pointing to the current allocation
8320 * - a duk_size_t indicating the full allocated size (always >= 'size')
8321 *
8322 * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
8323 * by user code, so that Duktape won't be able to resize it and won't
8324 * free it. This allows buffers to point to e.g. an externally
8325 * allocated structure such as a frame buffer.
8326 *
8327 * Unlike strings, no terminator byte (NUL) is guaranteed after the
8328 * data. This would be convenient, but would pad aligned user buffers
8329 * unnecessarily upwards in size. For instance, if user code requested
8330 * a 64-byte dynamic buffer, 65 bytes would actually be allocated which
8331 * would then potentially round upwards to perhaps 68 or 72 bytes.
8332 */
8333};
8334
8335/* Fixed buffer; data follows struct, with proper alignment guaranteed by
8336 * struct size.
8337 */
8338#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
8339#pragma pack(push, 8)
8340#endif
8341struct duk_hbuffer_fixed {
8342 /* A union is used here as a portable struct size / alignment trick:
8343 * by adding a 32-bit or a 64-bit (unused) union member, the size of
8344 * the struct is effectively forced to be a multiple of 4 or 8 bytes
8345 * (respectively) without increasing the size of the struct unless
8346 * necessary.
8347 */
8348 union {
8349 struct {
8350 duk_heaphdr hdr;
8351#if defined(DUK_USE_BUFLEN16)
8352 /* Stored in duk_heaphdr unused flags. */
8353#else
8354 duk_size_t size;
8355#endif
8356 } s;
8357#if (DUK_USE_ALIGN_BY == 4)
8358 duk_uint32_t dummy_for_align4;
8359#elif (DUK_USE_ALIGN_BY == 8)
8360 duk_double_t dummy_for_align8_1;
8361#if defined(DUK_USE_64BIT_OPS)
8362 duk_uint64_t dummy_for_align8_2;
8363#endif
8364#elif (DUK_USE_ALIGN_BY == 1)
8365 /* no extra padding */
8366#else
8367#error invalid DUK_USE_ALIGN_BY
8368#endif
8369 } u;
8370
8371 /*
8372 * Data follows the struct header. The struct size is padded by the
8373 * compiler based on the struct members. This guarantees that the
8374 * buffer data will be aligned-by-4 but not necessarily aligned-by-8.
8375 *
8376 * On platforms where alignment does not matter, the struct padding
8377 * could be removed (if there is any). On platforms where alignment
8378 * by 8 is required, the struct size must be forced to be a multiple
8379 * of 8 by some means. Without it, some user code may break, and also
8380 * Duktape itself breaks (e.g. the compiler stores duk_tvals in a
8381 * dynamic buffer).
8382 */
8383}
8384#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
8385__attribute__ ((aligned (8)))
8386#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
8387__attribute__ ((aligned (8)))
8388#endif
8389;
8390#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
8391#pragma pack(pop)
8392#endif
8393
8394/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
8395 * heap allocation primitives. Also used for external buffers when low memory
8396 * options are not used.
8397 */
8398struct duk_hbuffer_dynamic {
8399 duk_heaphdr hdr;
8400
8401#if defined(DUK_USE_BUFLEN16)
8402 /* Stored in duk_heaphdr unused flags. */
8403#else
8404 duk_size_t size;
8405#endif
8406
8407#if defined(DUK_USE_HEAPPTR16)
8408 /* Stored in duk_heaphdr h_extra16. */
8409#else
8410 void *curr_alloc; /* may be NULL if alloc_size == 0 */
8411#endif
8412
8413 /*
8414 * Allocation size for 'curr_alloc' is alloc_size. There is no
8415 * automatic NUL terminator for buffers (see above for rationale).
8416 *
8417 * 'curr_alloc' is explicitly allocated with heap allocation
8418 * primitives and will thus always have alignment suitable for
8419 * e.g. duk_tval and an IEEE double.
8420 */
8421};
8422
8423/* External buffer with 'curr_alloc' managed by user code and pointing to an
8424 * arbitrary address. When heap pointer compression is not used, this struct
8425 * has the same layout as duk_hbuffer_dynamic.
8426 */
8427struct duk_hbuffer_external {
8428 duk_heaphdr hdr;
8429
8430#if defined(DUK_USE_BUFLEN16)
8431 /* Stored in duk_heaphdr unused flags. */
8432#else
8433 duk_size_t size;
8434#endif
8435
8436 /* Cannot be compressed as a heap pointer because may point to
8437 * an arbitrary address.
8438 */
8439 void *curr_alloc; /* may be NULL if alloc_size == 0 */
8440};
8441
8442/*
8443 * Prototypes
8444 */
8445
8446DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
8447DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
8448
8449/* dynamic buffer ops */
8450DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
8451DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
8452
8453#endif /* DUK_HBUFFER_H_INCLUDED */
8454/* #include duk_hproxy.h */
8455#line 1 "duk_hproxy.h"
8456/*
8457 * Proxy object representation.
8458 */
8459
8460#if !defined(DUK_HPROXY_H_INCLUDED)
8461#define DUK_HPROXY_H_INCLUDED
8462
8463#if defined(DUK_USE_ASSERTIONS)
8464DUK_INTERNAL_DECL void duk_hproxy_assert_valid(duk_hproxy *h);
8465#define DUK_HPROXY_ASSERT_VALID(h) do { duk_hproxy_assert_valid((h)); } while (0)
8466#else
8467#define DUK_HPROXY_ASSERT_VALID(h) do {} while (0)
8468#endif
8469
8470struct duk_hproxy {
8471 /* Shared object part. */
8472 duk_hobject obj;
8473
8474 /* Proxy target object. */
8475 duk_hobject *target;
8476
8477 /* Proxy handlers (traps). */
8478 duk_hobject *handler;
8479};
8480
8481#endif /* DUK_HPROXY_H_INCLUDED */
8482/* #include duk_heap.h */
8483#line 1 "duk_heap.h"
8484/*
8485 * Heap structure.
8486 *
8487 * Heap contains allocated heap objects, interned strings, and built-in
8488 * strings for one or more threads.
8489 */
8490
8491#if !defined(DUK_HEAP_H_INCLUDED)
8492#define DUK_HEAP_H_INCLUDED
8493
8494/* alloc function typedefs in duktape.h */
8495
8496/*
8497 * Heap flags
8498 */
8499
8500#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
8501#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */
8502#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */
8503#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */
8504
8505#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
8506#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
8507 (heap)->flags |= (bits); \
8508 } while (0)
8509#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
8510 (heap)->flags &= ~(bits); \
8511 } while (0)
8512
8513#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8514#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8515#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8516#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8517
8518#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8519#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8520#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8521#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8522
8523#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8524#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8525#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8526#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8527
8528/*
8529 * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
8530 */
8531
8532#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
8533#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
8534#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
8535#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
8536#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
8537#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
8538#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
8539#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
8540
8541/*
8542 * Mark-and-sweep flags
8543 *
8544 * These are separate from heap level flags now but could be merged.
8545 * The heap structure only contains a 'base mark-and-sweep flags'
8546 * field and the GC caller can impose further flags.
8547 */
8548
8549/* Emergency mark-and-sweep: try extra hard, even at the cost of
8550 * performance.
8551 */
8552#define DUK_MS_FLAG_EMERGENCY (1U << 0)
8553
8554/* Postpone rescue decisions for reachable objects with FINALIZED set.
8555 * Used during finalize_list processing to avoid incorrect rescue
8556 * decisions due to finalize_list being a reachability root.
8557 */
8558#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 1)
8559
8560/* Don't compact objects; needed during object property table resize
8561 * to prevent a recursive resize. It would suffice to protect only the
8562 * current object being resized, but this is not yet implemented.
8563 */
8564#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 2)
8565
8566/*
8567 * Thread switching
8568 *
8569 * To switch heap->curr_thread, use the macro below so that interrupt counters
8570 * get updated correctly. The macro allows a NULL target thread because that
8571 * happens e.g. in call handling.
8572 */
8573
8574#if defined(DUK_USE_INTERRUPT_COUNTER)
8575#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
8576#else
8577#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
8578 (heap)->curr_thread = (newthr); \
8579 } while (0)
8580#endif
8581
8582/*
8583 * Stats
8584 */
8585
8586#if defined(DUK_USE_DEBUG)
8587#define DUK_STATS_INC(heap,fieldname) do { \
8588 (heap)->fieldname += 1; \
8589 } while (0)
8590#else
8591#define DUK_STATS_INC(heap,fieldname) do {} while (0)
8592#endif
8593
8594/*
8595 * Other heap related defines
8596 */
8597
8598/* Mark-and-sweep interval is relative to combined count of objects and
8599 * strings kept in the heap during the latest mark-and-sweep pass.
8600 * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
8601 * decreased by each (re)allocation attempt (regardless of size), and each
8602 * refzero processed object.
8603 *
8604 * 'SKIP' indicates how many (re)allocations to wait until a retry if
8605 * GC is skipped because there is no thread do it with yet (happens
8606 * only during init phases).
8607 */
8608#if defined(DUK_USE_REFERENCE_COUNTING)
8609#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
8610#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
8611#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
8612#else
8613#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
8614#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
8615#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
8616#endif
8617
8618/* GC torture. */
8619#if defined(DUK_USE_GC_TORTURE)
8620#define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0)
8621#else
8622#define DUK_GC_TORTURE(heap) do { } while (0)
8623#endif
8624
8625/* Stringcache is used for speeding up char-offset-to-byte-offset
8626 * translations for non-ASCII strings.
8627 */
8628#define DUK_HEAP_STRCACHE_SIZE 4
8629#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
8630
8631/* Some list management macros. */
8632#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr))
8633#if defined(DUK_USE_REFERENCE_COUNTING)
8634#define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr))
8635#endif
8636#if defined(DUK_USE_FINALIZER_SUPPORT)
8637#define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr))
8638#define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr))
8639#endif
8640
8641/*
8642 * Built-in strings
8643 */
8644
8645/* heap string indices are autogenerated in duk_strings.h */
8646#if defined(DUK_USE_ROM_STRINGS)
8647#define DUK_HEAP_GET_STRING(heap,idx) \
8648 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
8649#else /* DUK_USE_ROM_STRINGS */
8650#if defined(DUK_USE_HEAPPTR16)
8651#define DUK_HEAP_GET_STRING(heap,idx) \
8652 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
8653#else
8654#define DUK_HEAP_GET_STRING(heap,idx) \
8655 ((heap)->strs[(idx)])
8656#endif
8657#endif /* DUK_USE_ROM_STRINGS */
8658
8659/*
8660 * Raw memory calls: relative to heap, but no GC interaction
8661 */
8662
8663#define DUK_ALLOC_RAW(heap,size) \
8664 ((heap)->alloc_func((heap)->heap_udata, (size)))
8665
8666#define DUK_REALLOC_RAW(heap,ptr,newsize) \
8667 ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
8668
8669#define DUK_FREE_RAW(heap,ptr) \
8670 ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
8671
8672/*
8673 * Memory calls: relative to heap, GC interaction, but no error throwing.
8674 *
8675 * XXX: Currently a mark-and-sweep triggered by memory allocation will run
8676 * using the heap->heap_thread. This thread is also used for running
8677 * mark-and-sweep finalization; this is not ideal because it breaks the
8678 * isolation between multiple global environments.
8679 *
8680 * Notes:
8681 *
8682 * - DUK_FREE() is required to ignore NULL and any other possible return
8683 * value of a zero-sized alloc/realloc (same as ANSI C free()).
8684 *
8685 * - There is no DUK_REALLOC_ZEROED because we don't assume to know the
8686 * old size. Caller must zero the reallocated memory.
8687 *
8688 * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
8689 * by an allocation failure might invalidate the original 'ptr', thus
8690 * causing a realloc retry to use an invalid pointer. Example: we're
8691 * reallocating the value stack and a finalizer resizes the same value
8692 * stack during mark-and-sweep. The indirect variant requests for the
8693 * current location of the pointer being reallocated using a callback
8694 * right before every realloc attempt; this circuitous approach is used
8695 * to avoid strict aliasing issues in a more straightforward indirect
8696 * pointer (void **) approach. Note: the pointer in the storage
8697 * location is read but is NOT updated; the caller must do that.
8698 */
8699
8700/* callback for indirect reallocs, request for current pointer */
8701typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
8702
8703#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
8704#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
8705#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
8706#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
8707#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
8708
8709/*
8710 * Checked allocation, relative to a thread
8711 *
8712 * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
8713 * for convenience.
8714 */
8715
8716#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size))
8717#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size))
8718#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr))
8719
8720/*
8721 * Memory constants
8722 */
8723
8724#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this
8725 * many times. A single mark-and-sweep round is
8726 * not guaranteed to free all unreferenced memory
8727 * because of finalization (in fact, ANY number of
8728 * rounds is strictly not enough).
8729 */
8730
8731#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
8732 * for mark-and-sweep.
8733 */
8734
8735/*
8736 * Debugger support
8737 */
8738
8739/* Maximum number of breakpoints. Only breakpoints that are set are
8740 * consulted so increasing this has no performance impact.
8741 */
8742#define DUK_HEAP_MAX_BREAKPOINTS 16
8743
8744/* Opcode interval for a Date-based status/peek rate limit check. Only
8745 * relevant when debugger is attached. Requesting a timestamp may be a
8746 * slow operation on some platforms so this shouldn't be too low. On the
8747 * other hand a high value makes Duktape react to a pause request slowly.
8748 */
8749#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
8750
8751/* Milliseconds between status notify and transport peeks. */
8752#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
8753
8754/* Debugger pause flags. */
8755#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */
8756#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */
8757#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */
8758#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */
8759#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */
8760#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */
8761#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */
8762
8763struct duk_breakpoint {
8764 duk_hstring *filename;
8765 duk_uint32_t line;
8766};
8767
8768/*
8769 * String cache should ideally be at duk_hthread level, but that would
8770 * cause string finalization to slow down relative to the number of
8771 * threads; string finalization must check the string cache for "weak"
8772 * references to the string being finalized to avoid dead pointers.
8773 *
8774 * Thus, string caches are now at the heap level now.
8775 */
8776
8777struct duk_strcache_entry {
8778 duk_hstring *h;
8779 duk_uint32_t bidx;
8780 duk_uint32_t cidx;
8781};
8782
8783/*
8784 * Longjmp state, contains the information needed to perform a longjmp.
8785 * Longjmp related values are written to value1, value2, and iserror.
8786 */
8787
8788struct duk_ljstate {
8789 duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
8790 duk_small_uint_t type; /* longjmp type */
8791 duk_bool_t iserror; /* isError flag for yield */
8792 duk_tval value1; /* 1st related value (type specific) */
8793 duk_tval value2; /* 2nd related value (type specific) */
8794};
8795
8796#define DUK_ASSERT_LJSTATE_UNSET(heap) do { \
8797 DUK_ASSERT(heap != NULL); \
8798 DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \
8799 DUK_ASSERT(heap->lj.iserror == 0); \
8800 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \
8801 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \
8802 } while (0)
8803#define DUK_ASSERT_LJSTATE_SET(heap) do { \
8804 DUK_ASSERT(heap != NULL); \
8805 DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \
8806 } while (0)
8807
8808/*
8809 * Literal intern cache
8810 */
8811
8812struct duk_litcache_entry {
8813 const duk_uint8_t *addr;
8814 duk_hstring *h;
8815};
8816
8817/*
8818 * Main heap structure
8819 */
8820
8821#if defined(DUK_USE_ASSERTIONS)
8822DUK_INTERNAL_DECL void duk_heap_assert_valid(duk_heap *heap);
8823#define DUK_HEAP_ASSERT_VALID(heap) do { duk_heap_assert_valid((heap)); } while (0)
8824#else
8825#define DUK_HEAP_ASSERT_VALID(heap) do {} while (0)
8826#endif
8827
8828struct duk_heap {
8829 duk_small_uint_t flags;
8830
8831 /* Allocator functions. */
8832 duk_alloc_function alloc_func;
8833 duk_realloc_function realloc_func;
8834 duk_free_function free_func;
8835
8836 /* Heap udata, used for allocator functions but also for other heap
8837 * level callbacks like fatal function, pointer compression, etc.
8838 */
8839 void *heap_udata;
8840
8841 /* Fatal error handling, called e.g. when a longjmp() is needed but
8842 * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
8843 * declared as "noreturn" because doing that for typedefs is a bit
8844 * challenging portability-wise.
8845 */
8846 duk_fatal_function fatal_func;
8847
8848 /* Main list of allocated heap objects. Objects are either here,
8849 * in finalize_list waiting for processing, or in refzero_list
8850 * temporarily while a DECREF refzero cascade finishes.
8851 */
8852 duk_heaphdr *heap_allocated;
8853
8854 /* Temporary work list for freeing a cascade of objects when a DECREF
8855 * (or DECREF_NORZ) encounters a zero refcount. Using a work list
8856 * allows fixed C stack size when refcounts go to zero for a chain of
8857 * objects. Outside of DECREF this is always a NULL because DECREF is
8858 * processed without side effects (only memory free calls).
8859 */
8860#if defined(DUK_USE_REFERENCE_COUNTING)
8861 duk_heaphdr *refzero_list;
8862#endif
8863
8864#if defined(DUK_USE_FINALIZER_SUPPORT)
8865 /* Work list for objects to be finalized. */
8866 duk_heaphdr *finalize_list;
8867#if defined(DUK_USE_ASSERTIONS)
8868 /* Object whose finalizer is executing right now (no nesting). */
8869 duk_heaphdr *currently_finalizing;
8870#endif
8871#endif
8872
8873 /* Freelist for duk_activations and duk_catchers. */
8874#if defined(DUK_USE_CACHE_ACTIVATION)
8875 duk_activation *activation_free;
8876#endif
8877#if defined(DUK_USE_CACHE_CATCHER)
8878 duk_catcher *catcher_free;
8879#endif
8880
8881 /* Voluntary mark-and-sweep trigger counter. Intentionally signed
8882 * because we continue decreasing the value when voluntary GC cannot
8883 * run.
8884 */
8885#if defined(DUK_USE_VOLUNTARY_GC)
8886 duk_int_t ms_trigger_counter;
8887#endif
8888
8889 /* Mark-and-sweep recursion control: too deep recursion causes
8890 * multi-pass processing to avoid growing C stack without bound.
8891 */
8892 duk_uint_t ms_recursion_depth;
8893
8894 /* Mark-and-sweep flags automatically active (used for critical sections). */
8895 duk_small_uint_t ms_base_flags;
8896
8897 /* Mark-and-sweep running flag. Prevents re-entry, and also causes
8898 * refzero events to be ignored (= objects won't be queued to refzero_list).
8899 *
8900 * 0: mark-and-sweep not running
8901 * 1: mark-and-sweep is running
8902 * 2: heap destruction active or debugger active, prevent mark-and-sweep
8903 * and refzero processing (but mark-and-sweep not itself running)
8904 */
8905 duk_uint_t ms_running;
8906
8907 /* Mark-and-sweep prevent count, stacking. Used to avoid M&S side
8908 * effects (besides finalizers which are controlled separately) such
8909 * as compacting the string table or object property tables. This
8910 * is also bumped when ms_running is set to prevent recursive re-entry.
8911 * Can also be bumped when mark-and-sweep is not running.
8912 */
8913 duk_uint_t ms_prevent_count;
8914
8915 /* Finalizer processing prevent count, stacking. Bumped when finalizers
8916 * are processed to prevent recursive finalizer processing (first call site
8917 * processing finalizers handles all finalizers until the list is empty).
8918 * Can also be bumped explicitly to prevent finalizer execution.
8919 */
8920 duk_uint_t pf_prevent_count;
8921
8922 /* When processing finalize_list, don't actually run finalizers but
8923 * queue finalizable objects back to heap_allocated as is. This is
8924 * used during heap destruction to deal with finalizers that keep
8925 * on creating more finalizable garbage.
8926 */
8927 duk_uint_t pf_skip_finalizers;
8928
8929#if defined(DUK_USE_ASSERTIONS)
8930 /* Set when we're in a critical path where an error throw would cause
8931 * e.g. sandboxing/protected call violations or state corruption. This
8932 * is just used for asserts.
8933 */
8934 duk_bool_t error_not_allowed;
8935#endif
8936
8937#if defined(DUK_USE_ASSERTIONS)
8938 /* Set when heap is still being initialized, helps with writing
8939 * some assertions.
8940 */
8941 duk_bool_t heap_initializing;
8942#endif
8943
8944 /* Marker for detecting internal "double faults", errors thrown when
8945 * we're trying to create an error object, see duk_error_throw.c.
8946 */
8947 duk_bool_t creating_error;
8948
8949 /* Marker for indicating we're calling a user error augmentation
8950 * (errCreate/errThrow) function. Errors created/thrown during
8951 * such a call are not augmented.
8952 */
8953#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
8954 duk_bool_t augmenting_error;
8955#endif
8956
8957 /* Longjmp state. */
8958 duk_ljstate lj;
8959
8960 /* Heap thread, used internally and for finalization. */
8961 duk_hthread *heap_thread;
8962
8963 /* Current running thread. */
8964 duk_hthread *curr_thread;
8965
8966 /* Heap level "stash" object (e.g., various reachability roots). */
8967 duk_hobject *heap_object;
8968
8969 /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
8970 duk_int_t call_recursion_depth;
8971 duk_int_t call_recursion_limit;
8972
8973 /* Mix-in value for computing string hashes; should be reasonably unpredictable. */
8974 duk_uint32_t hash_seed;
8975
8976 /* Random number state for duk_util_tinyrandom.c. */
8977#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
8978#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
8979 duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */
8980#else
8981 duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */
8982#endif
8983#endif
8984
8985 /* Counter for unique local symbol creation. */
8986 /* XXX: When 64-bit types are available, it would be more efficient to
8987 * use a duk_uint64_t at least for incrementing but maybe also for
8988 * string formatting in the Symbol constructor.
8989 */
8990 duk_uint32_t sym_counter[2];
8991
8992 /* For manual debugging: instruction count based on executor and
8993 * interrupt counter book-keeping. Inspect debug logs to see how
8994 * they match up.
8995 */
8996#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
8997 duk_int_t inst_count_exec;
8998 duk_int_t inst_count_interrupt;
8999#endif
9000
9001 /* Debugger state. */
9002#if defined(DUK_USE_DEBUGGER_SUPPORT)
9003 /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */
9004 duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
9005 duk_debug_write_function dbg_write_cb; /* required */
9006 duk_debug_peek_function dbg_peek_cb;
9007 duk_debug_read_flush_function dbg_read_flush_cb;
9008 duk_debug_write_flush_function dbg_write_flush_cb;
9009 duk_debug_request_function dbg_request_cb;
9010 duk_debug_detached_function dbg_detached_cb;
9011 void *dbg_udata;
9012
9013 /* The following are only relevant when debugger is attached. */
9014 duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
9015 duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
9016 duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
9017 duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
9018 duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */
9019 duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */
9020 duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */
9021 duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
9022 duk_small_uint_t dbg_breakpoint_count;
9023 duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
9024 /* XXX: make active breakpoints actual copies instead of pointers? */
9025
9026 /* These are for rate limiting Status notifications and transport peeking. */
9027 duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
9028 duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
9029 duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
9030
9031 /* Used to support single-byte stream lookahead. */
9032 duk_bool_t dbg_have_next_byte;
9033 duk_uint8_t dbg_next_byte;
9034#endif /* DUK_USE_DEBUGGER_SUPPORT */
9035#if defined(DUK_USE_ASSERTIONS)
9036 duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */
9037#endif
9038
9039 /* String intern table (weak refs). */
9040#if defined(DUK_USE_STRTAB_PTRCOMP)
9041 duk_uint16_t *strtable16;
9042#else
9043 duk_hstring **strtable;
9044#endif
9045 duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */
9046 duk_uint32_t st_size; /* stringtable size */
9047#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
9048 duk_uint32_t st_count; /* string count for resize load factor checks */
9049#endif
9050 duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */
9051
9052 /* String access cache (codepoint offset -> byte offset) for fast string
9053 * character looping; 'weak' reference which needs special handling in GC.
9054 */
9055 duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE];
9056
9057#if defined(DUK_USE_LITCACHE_SIZE)
9058 /* Literal intern cache. When enabled, strings interned as literals
9059 * (e.g. duk_push_literal()) will be pinned and cached for the lifetime
9060 * of the heap.
9061 */
9062 duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE];
9063#endif
9064
9065 /* Built-in strings. */
9066#if defined(DUK_USE_ROM_STRINGS)
9067 /* No field needed when strings are in ROM. */
9068#else
9069#if defined(DUK_USE_HEAPPTR16)
9070 duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
9071#else
9072 duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
9073#endif
9074#endif
9075
9076 /* Stats. */
9077#if defined(DUK_USE_DEBUG)
9078 duk_int_t stats_exec_opcodes;
9079 duk_int_t stats_exec_interrupt;
9080 duk_int_t stats_exec_throw;
9081 duk_int_t stats_call_all;
9082 duk_int_t stats_call_tailcall;
9083 duk_int_t stats_call_ecmatoecma;
9084 duk_int_t stats_safecall_all;
9085 duk_int_t stats_safecall_nothrow;
9086 duk_int_t stats_safecall_throw;
9087 duk_int_t stats_ms_try_count;
9088 duk_int_t stats_ms_skip_count;
9089 duk_int_t stats_ms_emergency_count;
9090 duk_int_t stats_strtab_intern_hit;
9091 duk_int_t stats_strtab_intern_miss;
9092 duk_int_t stats_strtab_resize_check;
9093 duk_int_t stats_strtab_resize_grow;
9094 duk_int_t stats_strtab_resize_shrink;
9095 duk_int_t stats_strtab_litcache_hit;
9096 duk_int_t stats_strtab_litcache_miss;
9097 duk_int_t stats_strtab_litcache_pin;
9098 duk_int_t stats_object_realloc_props;
9099 duk_int_t stats_object_abandon_array;
9100 duk_int_t stats_getownpropdesc_count;
9101 duk_int_t stats_getownpropdesc_hit;
9102 duk_int_t stats_getownpropdesc_miss;
9103 duk_int_t stats_getpropdesc_count;
9104 duk_int_t stats_getpropdesc_hit;
9105 duk_int_t stats_getpropdesc_miss;
9106 duk_int_t stats_getprop_all;
9107 duk_int_t stats_getprop_arrayidx;
9108 duk_int_t stats_getprop_bufobjidx;
9109 duk_int_t stats_getprop_bufferidx;
9110 duk_int_t stats_getprop_bufferlen;
9111 duk_int_t stats_getprop_stringidx;
9112 duk_int_t stats_getprop_stringlen;
9113 duk_int_t stats_getprop_proxy;
9114 duk_int_t stats_getprop_arguments;
9115 duk_int_t stats_putprop_all;
9116 duk_int_t stats_putprop_arrayidx;
9117 duk_int_t stats_putprop_bufobjidx;
9118 duk_int_t stats_putprop_bufferidx;
9119 duk_int_t stats_putprop_proxy;
9120 duk_int_t stats_getvar_all;
9121 duk_int_t stats_putvar_all;
9122 duk_int_t stats_envrec_delayedcreate;
9123 duk_int_t stats_envrec_create;
9124 duk_int_t stats_envrec_newenv;
9125 duk_int_t stats_envrec_oldenv;
9126 duk_int_t stats_envrec_pushclosure;
9127#endif
9128};
9129
9130/*
9131 * Prototypes
9132 */
9133
9134DUK_INTERNAL_DECL
9135duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
9136 duk_realloc_function realloc_func,
9137 duk_free_function free_func,
9138 void *heap_udata,
9139 duk_fatal_function fatal_func);
9140DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
9141DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
9142DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
9143DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
9144DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
9145
9146DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
9147#if defined(DUK_USE_REFERENCE_COUNTING)
9148DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
9149#endif
9150#if defined(DUK_USE_FINALIZER_SUPPORT)
9151DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
9152DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
9153#endif
9154#if defined(DUK_USE_ASSERTIONS)
9155DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr);
9156#endif
9157#if defined(DUK_USE_INTERRUPT_COUNTER)
9158DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
9159#endif
9160
9161DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
9162DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
9163#if defined(DUK_USE_LITCACHE_SIZE)
9164DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen);
9165#endif
9166DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
9167DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
9168#if defined(DUK_USE_REFERENCE_COUNTING)
9169DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h);
9170#endif
9171DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev);
9172DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap);
9173DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap);
9174#if defined(DUK_USE_DEBUG)
9175DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap);
9176#endif
9177
9178DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
9179DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
9180
9181#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
9182DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
9183DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
9184DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
9185#endif
9186
9187DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
9188DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
9189DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size);
9190DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size);
9191DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
9192DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
9193DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
9194
9195DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
9196
9197#if defined(DUK_USE_FINALIZER_SUPPORT)
9198DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
9199DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
9200#endif /* DUK_USE_FINALIZER_SUPPORT */
9201
9202DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
9203
9204DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
9205
9206#endif /* DUK_HEAP_H_INCLUDED */
9207/* #include duk_debugger.h */
9208#line 1 "duk_debugger.h"
9209#if !defined(DUK_DEBUGGER_H_INCLUDED)
9210#define DUK_DEBUGGER_H_INCLUDED
9211
9212/* Debugger protocol version is defined in the public API header. */
9213
9214/* Initial bytes for markers. */
9215#define DUK_DBG_IB_EOM 0x00
9216#define DUK_DBG_IB_REQUEST 0x01
9217#define DUK_DBG_IB_REPLY 0x02
9218#define DUK_DBG_IB_ERROR 0x03
9219#define DUK_DBG_IB_NOTIFY 0x04
9220
9221/* Other initial bytes. */
9222#define DUK_DBG_IB_INT4 0x10
9223#define DUK_DBG_IB_STR4 0x11
9224#define DUK_DBG_IB_STR2 0x12
9225#define DUK_DBG_IB_BUF4 0x13
9226#define DUK_DBG_IB_BUF2 0x14
9227#define DUK_DBG_IB_UNUSED 0x15
9228#define DUK_DBG_IB_UNDEFINED 0x16
9229#define DUK_DBG_IB_NULL 0x17
9230#define DUK_DBG_IB_TRUE 0x18
9231#define DUK_DBG_IB_FALSE 0x19
9232#define DUK_DBG_IB_NUMBER 0x1a
9233#define DUK_DBG_IB_OBJECT 0x1b
9234#define DUK_DBG_IB_POINTER 0x1c
9235#define DUK_DBG_IB_LIGHTFUNC 0x1d
9236#define DUK_DBG_IB_HEAPPTR 0x1e
9237/* The short string/integer initial bytes starting from 0x60 don't have
9238 * defines now.
9239 */
9240
9241/* Error codes. */
9242#define DUK_DBG_ERR_UNKNOWN 0x00
9243#define DUK_DBG_ERR_UNSUPPORTED 0x01
9244#define DUK_DBG_ERR_TOOMANY 0x02
9245#define DUK_DBG_ERR_NOTFOUND 0x03
9246#define DUK_DBG_ERR_APPLICATION 0x04
9247
9248/* Commands and notifys initiated by Duktape. */
9249#define DUK_DBG_CMD_STATUS 0x01
9250#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */
9251#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */
9252#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */
9253#define DUK_DBG_CMD_THROW 0x05
9254#define DUK_DBG_CMD_DETACHING 0x06
9255#define DUK_DBG_CMD_APPNOTIFY 0x07
9256
9257/* Commands initiated by debug client. */
9258#define DUK_DBG_CMD_BASICINFO 0x10
9259#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
9260#define DUK_DBG_CMD_PAUSE 0x12
9261#define DUK_DBG_CMD_RESUME 0x13
9262#define DUK_DBG_CMD_STEPINTO 0x14
9263#define DUK_DBG_CMD_STEPOVER 0x15
9264#define DUK_DBG_CMD_STEPOUT 0x16
9265#define DUK_DBG_CMD_LISTBREAK 0x17
9266#define DUK_DBG_CMD_ADDBREAK 0x18
9267#define DUK_DBG_CMD_DELBREAK 0x19
9268#define DUK_DBG_CMD_GETVAR 0x1a
9269#define DUK_DBG_CMD_PUTVAR 0x1b
9270#define DUK_DBG_CMD_GETCALLSTACK 0x1c
9271#define DUK_DBG_CMD_GETLOCALS 0x1d
9272#define DUK_DBG_CMD_EVAL 0x1e
9273#define DUK_DBG_CMD_DETACH 0x1f
9274#define DUK_DBG_CMD_DUMPHEAP 0x20
9275#define DUK_DBG_CMD_GETBYTECODE 0x21
9276#define DUK_DBG_CMD_APPREQUEST 0x22
9277#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
9278#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
9279#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
9280
9281/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
9282 * The remaining flags are specific to the debugger.
9283 */
9284#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8)
9285#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9)
9286
9287#if defined(DUK_USE_DEBUGGER_SUPPORT)
9288DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
9289
9290DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
9291DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
9292
9293DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
9294DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
9295
9296DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
9297DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
9298DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
9299DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
9300/* XXX: exposed duk_debug_read_pointer */
9301/* XXX: exposed duk_debug_read_buffer */
9302/* XXX: exposed duk_debug_read_hbuffer */
9303#if 0
9304DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
9305#endif
9306#if defined(DUK_USE_DEBUGGER_INSPECT)
9307DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
9308#endif
9309DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
9310
9311DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
9312DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
9313DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
9314DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
9315#if defined(DUK_USE_DEBUGGER_INSPECT)
9316DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
9317#endif
9318DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
9319DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
9320DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
9321DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
9322DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
9323DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
9324DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
9325DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
9326DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
9327#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
9328DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
9329#endif
9330DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
9331DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
9332#if 0 /* unused */
9333DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
9334#endif
9335DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
9336DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
9337DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
9338DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
9339
9340DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
9341DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
9342#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
9343DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
9344#endif
9345
9346DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
9347DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
9348
9349DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
9350DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
9351
9352DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
9353DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
9354DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
9355DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
9356DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
9357#endif /* DUK_USE_DEBUGGER_SUPPORT */
9358
9359#endif /* DUK_DEBUGGER_H_INCLUDED */
9360/* #include duk_debug.h */
9361#line 1 "duk_debug.h"
9362/*
9363 * Debugging macros, DUK_DPRINT() and its variants in particular.
9364 *
9365 * DUK_DPRINT() allows formatted debug prints, and supports standard
9366 * and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
9367 *
9368 * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
9369 * for technical reasons. They are concretely used to hide 'x' from the
9370 * compiler when the corresponding log level is disabled. This allows
9371 * clean builds on non-C99 compilers, at the cost of more verbose code.
9372 * Examples:
9373 *
9374 * DUK_D(DUK_DPRINT("foo"));
9375 * DUK_DD(DUK_DDPRINT("foo"));
9376 * DUK_DDD(DUK_DDDPRINT("foo"));
9377 *
9378 * This approach is preferable to the old "double parentheses" hack because
9379 * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
9380 * no longer be added transparently without going through globals, which
9381 * works poorly with threading.
9382 */
9383
9384#if !defined(DUK_DEBUG_H_INCLUDED)
9385#define DUK_DEBUG_H_INCLUDED
9386
9387#if defined(DUK_USE_DEBUG)
9388
9389#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9390#define DUK_D(x) x
9391#else
9392#define DUK_D(x) do { } while (0) /* omit */
9393#endif
9394
9395#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9396#define DUK_DD(x) x
9397#else
9398#define DUK_DD(x) do { } while (0) /* omit */
9399#endif
9400
9401#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9402#define DUK_DDD(x) x
9403#else
9404#define DUK_DDD(x) do { } while (0) /* omit */
9405#endif
9406
9407/*
9408 * Exposed debug macros: debugging enabled
9409 */
9410
9411#if defined(DUK_USE_VARIADIC_MACROS)
9412
9413/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
9414 * possible compile time, but waste some space with shared function names.
9415 */
9416#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
9417
9418#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9419#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
9420#else
9421#define DUK_DPRINT(...)
9422#endif
9423
9424#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9425#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
9426#else
9427#define DUK_DDPRINT(...)
9428#endif
9429
9430#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9431#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
9432#else
9433#define DUK_DDDPRINT(...)
9434#endif
9435
9436#else /* DUK_USE_VARIADIC_MACROS */
9437
9438#define DUK__DEBUG_STASH(lev) \
9439 (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
9440 (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
9441 (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
9442 (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
9443 (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
9444 (void) (duk_debug_level_stash = (lev))
9445
9446/* Without variadic macros resort to comma expression trickery to handle debug
9447 * prints. This generates a lot of harmless warnings. These hacks are not
9448 * needed normally because DUK_D() and friends will hide the entire debug log
9449 * statement from the compiler.
9450 */
9451
9452#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9453#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
9454#else
9455#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
9456#endif
9457
9458#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9459#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
9460#else
9461#define DUK_DDPRINT 0 && /* args */
9462#endif
9463
9464#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9465#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
9466#else
9467#define DUK_DDDPRINT 0 && /* args */
9468#endif
9469
9470#endif /* DUK_USE_VARIADIC_MACROS */
9471
9472#else /* DUK_USE_DEBUG */
9473
9474/*
9475 * Exposed debug macros: debugging disabled
9476 */
9477
9478#define DUK_D(x) do { } while (0) /* omit */
9479#define DUK_DD(x) do { } while (0) /* omit */
9480#define DUK_DDD(x) do { } while (0) /* omit */
9481
9482#if defined(DUK_USE_VARIADIC_MACROS)
9483
9484#define DUK_DPRINT(...)
9485#define DUK_DDPRINT(...)
9486#define DUK_DDDPRINT(...)
9487
9488#else /* DUK_USE_VARIADIC_MACROS */
9489
9490#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
9491#define DUK_DDPRINT 0 && /* args */
9492#define DUK_DDDPRINT 0 && /* args */
9493
9494#endif /* DUK_USE_VARIADIC_MACROS */
9495
9496#endif /* DUK_USE_DEBUG */
9497
9498/*
9499 * Structs
9500 */
9501
9502#if defined(DUK_USE_DEBUG)
9503struct duk_fixedbuffer {
9504 duk_uint8_t *buffer;
9505 duk_size_t length;
9506 duk_size_t offset;
9507 duk_bool_t truncated;
9508};
9509#endif
9510
9511/*
9512 * Prototypes
9513 */
9514
9515#if defined(DUK_USE_DEBUG)
9516DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
9517#if 0 /*unused*/
9518DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
9519#endif
9520DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
9521
9522#if defined(DUK_USE_VARIADIC_MACROS)
9523DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
9524#else /* DUK_USE_VARIADIC_MACROS */
9525/* parameter passing, not thread safe */
9526#define DUK_DEBUG_STASH_SIZE 128
9527#if !defined(DUK_SINGLE_FILE)
9528DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
9529DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
9530DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
9531DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
9532#endif
9533DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
9534#endif /* DUK_USE_VARIADIC_MACROS */
9535
9536DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
9537DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
9538DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
9539DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
9540DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
9541DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
9542
9543#endif /* DUK_USE_DEBUG */
9544
9545#endif /* DUK_DEBUG_H_INCLUDED */
9546/* #include duk_error.h */
9547#line 1 "duk_error.h"
9548/*
9549 * Error handling macros, assertion macro, error codes.
9550 *
9551 * There are three types of 'errors':
9552 *
9553 * 1. Ordinary errors relative to a thread, cause a longjmp, catchable.
9554 * 2. Fatal errors relative to a heap, cause fatal handler to be called.
9555 * 3. Fatal errors without context, cause the default (not heap specific)
9556 * fatal handler to be called.
9557 *
9558 * Fatal errors without context are used by debug code such as assertions.
9559 * By providing a fatal error handler for a Duktape heap, user code can
9560 * avoid fatal errors without context in non-debug builds.
9561 */
9562
9563#if !defined(DUK_ERROR_H_INCLUDED)
9564#define DUK_ERROR_H_INCLUDED
9565
9566/*
9567 * Error codes: defined in duktape.h
9568 *
9569 * Error codes are used as a shorthand to throw exceptions from inside
9570 * the implementation. The appropriate ECMAScript object is constructed
9571 * based on the code. ECMAScript code throws objects directly. The error
9572 * codes are defined in the public API header because they are also used
9573 * by calling code.
9574 */
9575
9576/*
9577 * Normal error
9578 *
9579 * Normal error is thrown with a longjmp() through the current setjmp()
9580 * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
9581 * identifies the throwing thread.
9582 *
9583 * Error formatting is usually unnecessary. The error macros provide a
9584 * zero argument version (no formatting) and separate macros for small
9585 * argument counts. Variadic macros are not used to avoid portability
9586 * issues and avoid the need for stash-based workarounds when they're not
9587 * available. Vararg calls are avoided for non-formatted error calls
9588 * because vararg call sites are larger than normal, and there are a lot
9589 * of call sites with no formatting.
9590 *
9591 * Note that special formatting provided by debug macros is NOT available.
9592 *
9593 * The _RAW variants allow the caller to specify file and line. This makes
9594 * it easier to write checked calls which want to use the call site of the
9595 * checked function, not the error macro call inside the checked function.
9596 */
9597
9598#if defined(DUK_USE_VERBOSE_ERRORS)
9599
9600/* Because there are quite many call sites, pack error code (require at most
9601 * 8-bit) into a single argument.
9602 */
9603#define DUK_ERROR(thr,err,msg) do { \
9604 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9605 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9606 duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
9607 } while (0)
9608#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
9609 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9610 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9611 duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
9612 } while (0)
9613
9614#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
9615 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9616 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9617 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
9618 } while (0)
9619#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
9620 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9621 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9622 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
9623 } while (0)
9624
9625#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
9626 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9627 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9628 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
9629 } while (0)
9630#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
9631 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9632 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9633 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
9634 } while (0)
9635
9636#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
9637 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9638 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9639 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
9640 } while (0)
9641#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
9642 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9643 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9644 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
9645 } while (0)
9646
9647#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
9648 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9649 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9650 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
9651 } while (0)
9652#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
9653 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9654 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9655 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
9656 } while (0)
9657
9658#else /* DUK_USE_VERBOSE_ERRORS */
9659
9660#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
9661#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
9662
9663#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
9664#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9665
9666#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
9667#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9668
9669#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
9670#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9671
9672#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
9673#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9674
9675#endif /* DUK_USE_VERBOSE_ERRORS */
9676
9677/*
9678 * Fatal error without context
9679 *
9680 * The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
9681 */
9682
9683#define DUK_FATAL_WITHOUT_CONTEXT(msg) \
9684 duk_default_fatal_handler(NULL, (msg))
9685
9686/*
9687 * Error throwing helpers
9688 *
9689 * The goal is to provide verbose and configurable error messages. Call
9690 * sites should be clean in source code and compile to a small footprint.
9691 * Small footprint is also useful for performance because small cold paths
9692 * reduce code cache pressure. Adding macros here only makes sense if there
9693 * are enough call sites to get concrete benefits.
9694 *
9695 * DUK_ERROR_xxx() macros are generic and can be used anywhere.
9696 *
9697 * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
9698 * the "return DUK_RET_xxx;" shorthand is available for low memory targets.
9699 * The DUK_DCERROR_xxx() macros always either throw or perform a
9700 * 'return DUK_RET_xxx' from the calling function.
9701 */
9702
9703#if defined(DUK_USE_VERBOSE_ERRORS)
9704/* Verbose errors with key/value summaries (non-paranoid) or without key/value
9705 * summaries (paranoid, for some security sensitive environments), the paranoid
9706 * vs. non-paranoid distinction affects only a few specific errors.
9707 */
9708#if defined(DUK_USE_PARANOID_ERRORS)
9709#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9710 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
9711 } while (0)
9712#else /* DUK_USE_PARANOID_ERRORS */
9713#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9714 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
9715 } while (0)
9716#endif /* DUK_USE_PARANOID_ERRORS */
9717
9718#define DUK_ERROR_INTERNAL(thr) do { \
9719 duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9720 } while (0)
9721#define DUK_DCERROR_INTERNAL(thr) do { \
9722 DUK_ERROR_INTERNAL((thr)); \
9723 return 0; \
9724 } while (0)
9725#define DUK_ERROR_ALLOC_FAILED(thr) do { \
9726 duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9727 } while (0)
9728#define DUK_ERROR_UNSUPPORTED(thr) do { \
9729 DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
9730 } while (0)
9731#define DUK_DCERROR_UNSUPPORTED(thr) do { \
9732 DUK_ERROR_UNSUPPORTED((thr)); \
9733 return 0; \
9734 } while (0)
9735#define DUK_ERROR_ERROR(thr,msg) do { \
9736 duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
9737 } while (0)
9738#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
9739 duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
9740 } while (0)
9741#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
9742 duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9743 } while (0)
9744#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
9745 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
9746 } while (0)
9747#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
9748 DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
9749 return 0; \
9750 } while (0)
9751#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
9752 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
9753 } while (0)
9754#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
9755 DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
9756 return 0; \
9757 } while (0)
9758#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
9759 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
9760 } while (0)
9761#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
9762 DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
9763 return 0; \
9764 } while (0)
9765#define DUK_ERROR_RANGE(thr,msg) do { \
9766 duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
9767 } while (0)
9768#define DUK_ERROR_EVAL(thr,msg) do { \
9769 DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
9770 } while (0)
9771#define DUK_ERROR_REFERENCE(thr,msg) do { \
9772 DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
9773 } while (0)
9774#define DUK_ERROR_SYNTAX(thr,msg) do { \
9775 DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
9776 } while (0)
9777#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
9778 duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9779 } while (0)
9780#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
9781 DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
9782 return 0; \
9783 } while (0)
9784#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
9785 duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9786 } while (0)
9787#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
9788 DUK_ERROR_TYPE_INVALID_STATE((thr)); \
9789 return 0; \
9790 } while (0)
9791#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9792 duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9793 } while (0)
9794#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9795 DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
9796 } while (0)
9797#define DUK_ERROR_TYPE(thr,msg) do { \
9798 DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
9799 } while (0)
9800#define DUK_ERROR_URI(thr,msg) do { \
9801 DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
9802 } while (0)
9803#else /* DUK_USE_VERBOSE_ERRORS */
9804/* Non-verbose errors for low memory targets: no file, line, or message. */
9805
9806#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9807 duk_err_type((thr)); \
9808 } while (0)
9809
9810#define DUK_ERROR_INTERNAL(thr) do { \
9811 duk_err_error((thr)); \
9812 } while (0)
9813#define DUK_DCERROR_INTERNAL(thr) do { \
9814 DUK_UNREF((thr)); \
9815 return DUK_RET_ERROR; \
9816 } while (0)
9817#define DUK_ERROR_ALLOC_FAILED(thr) do { \
9818 duk_err_error((thr)); \
9819 } while (0)
9820#define DUK_ERROR_UNSUPPORTED(thr) do { \
9821 duk_err_error((thr)); \
9822 } while (0)
9823#define DUK_DCERROR_UNSUPPORTED(thr) do { \
9824 DUK_UNREF((thr)); \
9825 return DUK_RET_ERROR; \
9826 } while (0)
9827#define DUK_ERROR_ERROR(thr,msg) do { \
9828 duk_err_error((thr)); \
9829 } while (0)
9830#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
9831 duk_err_range((thr)); \
9832 } while (0)
9833#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
9834 duk_err_range((thr)); \
9835 } while (0)
9836#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
9837 duk_err_range((thr)); \
9838 } while (0)
9839#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
9840 DUK_UNREF((thr)); \
9841 return DUK_RET_RANGE_ERROR; \
9842 } while (0)
9843#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
9844 duk_err_range((thr)); \
9845 } while (0)
9846#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
9847 DUK_UNREF((thr)); \
9848 return DUK_RET_RANGE_ERROR; \
9849 } while (0)
9850#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
9851 duk_err_range((thr)); \
9852 } while (0)
9853#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
9854 DUK_UNREF((thr)); \
9855 return DUK_RET_RANGE_ERROR; \
9856 } while (0)
9857#define DUK_ERROR_RANGE(thr,msg) do { \
9858 duk_err_range((thr)); \
9859 } while (0)
9860#define DUK_ERROR_EVAL(thr,msg) do { \
9861 duk_err_eval((thr)); \
9862 } while (0)
9863#define DUK_ERROR_REFERENCE(thr,msg) do { \
9864 duk_err_reference((thr)); \
9865 } while (0)
9866#define DUK_ERROR_SYNTAX(thr,msg) do { \
9867 duk_err_syntax((thr)); \
9868 } while (0)
9869#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
9870 duk_err_type((thr)); \
9871 } while (0)
9872#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
9873 DUK_UNREF((thr)); \
9874 return DUK_RET_TYPE_ERROR; \
9875 } while (0)
9876#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
9877 duk_err_type((thr)); \
9878 } while (0)
9879#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
9880 duk_err_type((thr)); \
9881 } while (0)
9882#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9883 duk_err_type((thr)); \
9884 } while (0)
9885#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9886 DUK_UNREF((thr)); \
9887 return DUK_RET_TYPE_ERROR; \
9888 } while (0)
9889#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9890 duk_err_type((thr)); \
9891 } while (0)
9892#define DUK_ERROR_TYPE(thr,msg) do { \
9893 duk_err_type((thr)); \
9894 } while (0)
9895#define DUK_ERROR_URI(thr,msg) do { \
9896 duk_err_uri((thr)); \
9897 } while (0)
9898#endif /* DUK_USE_VERBOSE_ERRORS */
9899
9900/*
9901 * Assert macro: failure causes a fatal error.
9902 *
9903 * NOTE: since the assert macro doesn't take a heap/context argument, there's
9904 * no way to look up a heap/context specific fatal error handler which may have
9905 * been given by the application. Instead, assertion failures always use the
9906 * internal default fatal error handler; it can be replaced via duk_config.h
9907 * and then applies to all Duktape heaps.
9908 */
9909
9910#if defined(DUK_USE_ASSERTIONS)
9911
9912/* The message should be a compile time constant without formatting (less risk);
9913 * we don't care about assertion text size because they're not used in production
9914 * builds.
9915 */
9916#define DUK_ASSERT(x) do { \
9917 if (!(x)) { \
9918 DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
9919 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
9920 } \
9921 } while (0)
9922
9923/* Assertion compatible inside a comma expression, evaluates to void. */
9924#define DUK_ASSERT_EXPR(x) \
9925 ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
9926 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
9927
9928#else /* DUK_USE_ASSERTIONS */
9929
9930#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
9931
9932#define DUK_ASSERT_EXPR(x) ((void) 0)
9933
9934#endif /* DUK_USE_ASSERTIONS */
9935
9936/* this variant is used when an assert would generate a compile warning by
9937 * being always true (e.g. >= 0 comparison for an unsigned value
9938 */
9939#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
9940
9941/*
9942 * Assertion helpers
9943 */
9944
9945#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
9946#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
9947 DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
9948 } while (0)
9949#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
9950 if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
9951 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
9952 } \
9953 } while (0)
9954#else
9955#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
9956#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
9957#endif
9958
9959#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
9960
9961#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
9962#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
9963 duk_double_union duk__assert_tmp_du; \
9964 duk__assert_tmp_du.d = (dval); \
9965 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
9966 } while (0)
9967#else
9968#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
9969#endif
9970
9971#define DUK_ASSERT_VS_SPACE(thr) \
9972 DUK_ASSERT(thr->valstack_top < thr->valstack_end)
9973
9974/*
9975 * Helper to initialize a memory area (e.g. struct) with garbage when
9976 * assertions enabled.
9977 */
9978
9979#if defined(DUK_USE_ASSERTIONS)
9980#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
9981 duk_memset_unsafe((void *) (ptr), 0x5a, size); \
9982 } while (0)
9983#else
9984#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
9985#endif
9986
9987/*
9988 * Helper for valstack space
9989 *
9990 * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
9991 * required for its own use, and any child calls which are not (a) Duktape API calls
9992 * or (b) Duktape calls which involve extending the valstack (e.g. getter call).
9993 */
9994
9995#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
9996 * API calls in addition to function's own use
9997 */
9998#if defined(DUK_USE_ASSERTIONS)
9999#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
10000 DUK_ASSERT((thr) != NULL); \
10001 DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
10002 } while (0)
10003#else
10004#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
10005#endif
10006
10007/*
10008 * Prototypes
10009 */
10010
10011#if defined(DUK_USE_VERBOSE_ERRORS)
10012DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
10013DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...));
10014#else /* DUK_USE_VERBOSE_ERRORS */
10015DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
10016#endif /* DUK_USE_VERBOSE_ERRORS */
10017
10018#if defined(DUK_USE_VERBOSE_ERRORS)
10019DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line));
10020#else
10021DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
10022#endif
10023
10024DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
10025
10026#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */
10027#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */
10028
10029#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
10030DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags);
10031#endif
10032#if defined(DUK_USE_AUGMENT_ERROR_THROW)
10033DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
10034#endif
10035
10036#if defined(DUK_USE_VERBOSE_ERRORS)
10037#if defined(DUK_USE_PARANOID_ERRORS)
10038DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
10039#else
10040DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name));
10041#endif
10042DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10043DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10044DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
10045DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
10046DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10047DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
10048DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10049DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10050DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
10051#else /* DUK_VERBOSE_ERRORS */
10052DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
10053DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
10054DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
10055DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
10056DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
10057DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
10058DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
10059#endif /* DUK_VERBOSE_ERRORS */
10060
10061DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
10062
10063DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
10064
10065DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val);
10066#if defined(DUK_USE_DEBUGGER_SUPPORT)
10067DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr);
10068#endif
10069
10070DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
10071
10072#endif /* DUK_ERROR_H_INCLUDED */
10073/* #include duk_unicode.h */
10074#line 1 "duk_unicode.h"
10075/*
10076 * Unicode helpers
10077 */
10078
10079#if !defined(DUK_UNICODE_H_INCLUDED)
10080#define DUK_UNICODE_H_INCLUDED
10081
10082/*
10083 * UTF-8 / XUTF-8 / CESU-8 constants
10084 */
10085
10086#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */
10087#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
10088#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */
10089#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
10090
10091/*
10092 * Useful Unicode codepoints
10093 *
10094 * Integer constants must be signed to avoid unexpected coercions
10095 * in comparisons.
10096 */
10097
10098#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */
10099#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */
10100#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
10101
10102/*
10103 * ASCII character constants
10104 *
10105 * C character literals like 'x' have a platform specific value and do
10106 * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use
10107 * these (admittedly awkward) constants instead. These constants must
10108 * also have signed values to avoid unexpected coercions in comparisons.
10109 *
10110 * http://en.wikipedia.org/wiki/ASCII
10111 */
10112
10113#define DUK_ASC_NUL 0x00
10114#define DUK_ASC_SOH 0x01
10115#define DUK_ASC_STX 0x02
10116#define DUK_ASC_ETX 0x03
10117#define DUK_ASC_EOT 0x04
10118#define DUK_ASC_ENQ 0x05
10119#define DUK_ASC_ACK 0x06
10120#define DUK_ASC_BEL 0x07
10121#define DUK_ASC_BS 0x08
10122#define DUK_ASC_HT 0x09
10123#define DUK_ASC_LF 0x0a
10124#define DUK_ASC_VT 0x0b
10125#define DUK_ASC_FF 0x0c
10126#define DUK_ASC_CR 0x0d
10127#define DUK_ASC_SO 0x0e
10128#define DUK_ASC_SI 0x0f
10129#define DUK_ASC_DLE 0x10
10130#define DUK_ASC_DC1 0x11
10131#define DUK_ASC_DC2 0x12
10132#define DUK_ASC_DC3 0x13
10133#define DUK_ASC_DC4 0x14
10134#define DUK_ASC_NAK 0x15
10135#define DUK_ASC_SYN 0x16
10136#define DUK_ASC_ETB 0x17
10137#define DUK_ASC_CAN 0x18
10138#define DUK_ASC_EM 0x19
10139#define DUK_ASC_SUB 0x1a
10140#define DUK_ASC_ESC 0x1b
10141#define DUK_ASC_FS 0x1c
10142#define DUK_ASC_GS 0x1d
10143#define DUK_ASC_RS 0x1e
10144#define DUK_ASC_US 0x1f
10145#define DUK_ASC_SPACE 0x20
10146#define DUK_ASC_EXCLAMATION 0x21
10147#define DUK_ASC_DOUBLEQUOTE 0x22
10148#define DUK_ASC_HASH 0x23
10149#define DUK_ASC_DOLLAR 0x24
10150#define DUK_ASC_PERCENT 0x25
10151#define DUK_ASC_AMP 0x26
10152#define DUK_ASC_SINGLEQUOTE 0x27
10153#define DUK_ASC_LPAREN 0x28
10154#define DUK_ASC_RPAREN 0x29
10155#define DUK_ASC_STAR 0x2a
10156#define DUK_ASC_PLUS 0x2b
10157#define DUK_ASC_COMMA 0x2c
10158#define DUK_ASC_MINUS 0x2d
10159#define DUK_ASC_PERIOD 0x2e
10160#define DUK_ASC_SLASH 0x2f
10161#define DUK_ASC_0 0x30
10162#define DUK_ASC_1 0x31
10163#define DUK_ASC_2 0x32
10164#define DUK_ASC_3 0x33
10165#define DUK_ASC_4 0x34
10166#define DUK_ASC_5 0x35
10167#define DUK_ASC_6 0x36
10168#define DUK_ASC_7 0x37
10169#define DUK_ASC_8 0x38
10170#define DUK_ASC_9 0x39
10171#define DUK_ASC_COLON 0x3a
10172#define DUK_ASC_SEMICOLON 0x3b
10173#define DUK_ASC_LANGLE 0x3c
10174#define DUK_ASC_EQUALS 0x3d
10175#define DUK_ASC_RANGLE 0x3e
10176#define DUK_ASC_QUESTION 0x3f
10177#define DUK_ASC_ATSIGN 0x40
10178#define DUK_ASC_UC_A 0x41
10179#define DUK_ASC_UC_B 0x42
10180#define DUK_ASC_UC_C 0x43
10181#define DUK_ASC_UC_D 0x44
10182#define DUK_ASC_UC_E 0x45
10183#define DUK_ASC_UC_F 0x46
10184#define DUK_ASC_UC_G 0x47
10185#define DUK_ASC_UC_H 0x48
10186#define DUK_ASC_UC_I 0x49
10187#define DUK_ASC_UC_J 0x4a
10188#define DUK_ASC_UC_K 0x4b
10189#define DUK_ASC_UC_L 0x4c
10190#define DUK_ASC_UC_M 0x4d
10191#define DUK_ASC_UC_N 0x4e
10192#define DUK_ASC_UC_O 0x4f
10193#define DUK_ASC_UC_P 0x50
10194#define DUK_ASC_UC_Q 0x51
10195#define DUK_ASC_UC_R 0x52
10196#define DUK_ASC_UC_S 0x53
10197#define DUK_ASC_UC_T 0x54
10198#define DUK_ASC_UC_U 0x55
10199#define DUK_ASC_UC_V 0x56
10200#define DUK_ASC_UC_W 0x57
10201#define DUK_ASC_UC_X 0x58
10202#define DUK_ASC_UC_Y 0x59
10203#define DUK_ASC_UC_Z 0x5a
10204#define DUK_ASC_LBRACKET 0x5b
10205#define DUK_ASC_BACKSLASH 0x5c
10206#define DUK_ASC_RBRACKET 0x5d
10207#define DUK_ASC_CARET 0x5e
10208#define DUK_ASC_UNDERSCORE 0x5f
10209#define DUK_ASC_GRAVE 0x60
10210#define DUK_ASC_LC_A 0x61
10211#define DUK_ASC_LC_B 0x62
10212#define DUK_ASC_LC_C 0x63
10213#define DUK_ASC_LC_D 0x64
10214#define DUK_ASC_LC_E 0x65
10215#define DUK_ASC_LC_F 0x66
10216#define DUK_ASC_LC_G 0x67
10217#define DUK_ASC_LC_H 0x68
10218#define DUK_ASC_LC_I 0x69
10219#define DUK_ASC_LC_J 0x6a
10220#define DUK_ASC_LC_K 0x6b
10221#define DUK_ASC_LC_L 0x6c
10222#define DUK_ASC_LC_M 0x6d
10223#define DUK_ASC_LC_N 0x6e
10224#define DUK_ASC_LC_O 0x6f
10225#define DUK_ASC_LC_P 0x70
10226#define DUK_ASC_LC_Q 0x71
10227#define DUK_ASC_LC_R 0x72
10228#define DUK_ASC_LC_S 0x73
10229#define DUK_ASC_LC_T 0x74
10230#define DUK_ASC_LC_U 0x75
10231#define DUK_ASC_LC_V 0x76
10232#define DUK_ASC_LC_W 0x77
10233#define DUK_ASC_LC_X 0x78
10234#define DUK_ASC_LC_Y 0x79
10235#define DUK_ASC_LC_Z 0x7a
10236#define DUK_ASC_LCURLY 0x7b
10237#define DUK_ASC_PIPE 0x7c
10238#define DUK_ASC_RCURLY 0x7d
10239#define DUK_ASC_TILDE 0x7e
10240#define DUK_ASC_DEL 0x7f
10241
10242/*
10243 * Miscellaneous
10244 */
10245
10246/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase
10247 * to lowercase.
10248 */
10249#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20)
10250
10251/*
10252 * Unicode tables
10253 */
10254
10255#if defined(DUK_USE_SOURCE_NONBMP)
10256/*
10257 * Automatically generated by extract_chars.py, do not edit!
10258 */
10259
10260extern const duk_uint8_t duk_unicode_ids_noa[1116];
10261#else
10262/*
10263 * Automatically generated by extract_chars.py, do not edit!
10264 */
10265
10266extern const duk_uint8_t duk_unicode_ids_noabmp[625];
10267#endif
10268
10269#if defined(DUK_USE_SOURCE_NONBMP)
10270/*
10271 * Automatically generated by extract_chars.py, do not edit!
10272 */
10273
10274extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
10275#else
10276/*
10277 * Automatically generated by extract_chars.py, do not edit!
10278 */
10279
10280extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
10281#endif
10282
10283#if defined(DUK_USE_SOURCE_NONBMP)
10284/*
10285 * Automatically generated by extract_chars.py, do not edit!
10286 */
10287
10288extern const duk_uint8_t duk_unicode_idp_m_ids_noa[576];
10289#else
10290/*
10291 * Automatically generated by extract_chars.py, do not edit!
10292 */
10293
10294extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358];
10295#endif
10296
10297/*
10298 * Automatically generated by extract_caseconv.py, do not edit!
10299 */
10300
10301extern const duk_uint8_t duk_unicode_caseconv_uc[1411];
10302extern const duk_uint8_t duk_unicode_caseconv_lc[706];
10303
10304#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
10305/*
10306 * Automatically generated by extract_caseconv.py, do not edit!
10307 */
10308
10309extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
10310#endif
10311
10312#if defined(DUK_USE_REGEXP_CANON_BITMAP)
10313/*
10314 * Automatically generated by extract_caseconv.py, do not edit!
10315 */
10316
10317#define DUK_CANON_BITMAP_BLKSIZE 32
10318#define DUK_CANON_BITMAP_BLKSHIFT 5
10319#define DUK_CANON_BITMAP_BLKMASK 31
10320extern const duk_uint8_t duk_unicode_re_canon_bitmap[256];
10321#endif
10322
10323/*
10324 * Extern
10325 */
10326
10327/* duk_unicode_support.c */
10328#if !defined(DUK_SINGLE_FILE)
10329DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
10330DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
10331DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
10332DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
10333DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
10334DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
10335DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
10336DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
10337#endif /* !DUK_SINGLE_FILE */
10338
10339/*
10340 * Prototypes
10341 */
10342
10343DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
10344#if defined(DUK_USE_ASSERTIONS)
10345DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
10346#endif
10347DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
10348DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
10349DUK_INTERNAL_DECL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp);
10350DUK_INTERNAL_DECL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end);
10351DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
10352DUK_INTERNAL_DECL duk_bool_t duk_unicode_is_utf8_compatible(const duk_uint8_t *buf, duk_size_t len);
10353DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
10354DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
10355DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
10356DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
10357DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
10358DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
10359#if defined(DUK_USE_REGEXP_SUPPORT)
10360DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
10361DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
10362#endif
10363
10364#endif /* DUK_UNICODE_H_INCLUDED */
10365/* #include duk_json.h */
10366#line 1 "duk_json.h"
10367/*
10368 * Defines for JSON, especially duk_bi_json.c.
10369 */
10370
10371#if !defined(DUK_JSON_H_INCLUDED)
10372#define DUK_JSON_H_INCLUDED
10373
10374/* Encoding/decoding flags */
10375#define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */
10376#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */
10377#define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */
10378#define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */
10379
10380/* How much stack to require on entry to object/array encode */
10381#define DUK_JSON_ENC_REQSTACK 32
10382
10383/* How much stack to require on entry to object/array decode */
10384#define DUK_JSON_DEC_REQSTACK 32
10385
10386/* How large a loop detection stack to use */
10387#define DUK_JSON_ENC_LOOPARRAY 64
10388
10389/* Encoding state. Heap object references are all borrowed. */
10390typedef struct {
10391 duk_hthread *thr;
10392 duk_bufwriter_ctx bw; /* output bufwriter */
10393 duk_hobject *h_replacer; /* replacer function */
10394 duk_hstring *h_gap; /* gap (if empty string, NULL) */
10395 duk_idx_t idx_proplist; /* explicit PropertyList */
10396 duk_idx_t idx_loop; /* valstack index of loop detection object */
10397 duk_small_uint_t flags;
10398 duk_small_uint_t flag_ascii_only;
10399 duk_small_uint_t flag_avoid_key_quotes;
10400#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10401 duk_small_uint_t flag_ext_custom;
10402 duk_small_uint_t flag_ext_compatible;
10403 duk_small_uint_t flag_ext_custom_or_compatible;
10404#endif
10405 duk_uint_t recursion_depth;
10406 duk_uint_t recursion_limit;
10407 duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
10408#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10409 duk_small_uint_t stridx_custom_undefined;
10410 duk_small_uint_t stridx_custom_nan;
10411 duk_small_uint_t stridx_custom_neginf;
10412 duk_small_uint_t stridx_custom_posinf;
10413 duk_small_uint_t stridx_custom_function;
10414#endif
10415 duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
10416} duk_json_enc_ctx;
10417
10418typedef struct {
10419 duk_hthread *thr;
10420 const duk_uint8_t *p;
10421 const duk_uint8_t *p_start;
10422 const duk_uint8_t *p_end;
10423 duk_idx_t idx_reviver;
10424 duk_small_uint_t flags;
10425#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10426 duk_small_uint_t flag_ext_custom;
10427 duk_small_uint_t flag_ext_compatible;
10428 duk_small_uint_t flag_ext_custom_or_compatible;
10429#endif
10430 duk_int_t recursion_depth;
10431 duk_int_t recursion_limit;
10432} duk_json_dec_ctx;
10433
10434#endif /* DUK_JSON_H_INCLUDED */
10435/* #include duk_js.h */
10436#line 1 "duk_js.h"
10437/*
10438 * ECMAScript execution, support primitives.
10439 */
10440
10441#if !defined(DUK_JS_H_INCLUDED)
10442#define DUK_JS_H_INCLUDED
10443
10444/* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */
10445#define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */
10446#define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */
10447#define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */
10448#define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */
10449#define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */
10450#define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */
10451#define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */
10452
10453/* Flags for duk_js_equals_helper(). */
10454#define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */
10455#define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */
10456
10457/* Flags for duk_js_compare_helper(). */
10458#define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */
10459#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */
10460
10461/* conversions, coercions, comparison, etc */
10462DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
10463DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
10464DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
10465DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
10466DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
10467DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
10468DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
10469DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen);
10470#if !defined(DUK_USE_HSTRING_ARRIDX)
10471DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h);
10472DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h);
10473#endif
10474DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
10475DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2);
10476DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
10477#if 0 /* unused */
10478DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
10479#endif
10480DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
10481DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10482#if defined(DUK_USE_SYMBOL_BUILTIN)
10483DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10484#endif
10485DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10486DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
10487DUK_INTERNAL_DECL duk_bool_t duk_js_isarray_hobject(duk_hobject *h);
10488DUK_INTERNAL_DECL duk_bool_t duk_js_isarray(duk_tval *tv);
10489
10490/* arithmetic */
10491DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y);
10492DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y);
10493
10494#define duk_js_equals(thr,tv_x,tv_y) \
10495 duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
10496#define duk_js_strict_equals(tv_x,tv_y) \
10497 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
10498#define duk_js_samevalue(tv_x,tv_y) \
10499 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
10500
10501/* E5 Sections 11.8.1, 11.8.5; x < y */
10502#define duk_js_lessthan(thr,tv_x,tv_y) \
10503 duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
10504
10505/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */
10506#define duk_js_greaterthan(thr,tv_x,tv_y) \
10507 duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
10508
10509/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */
10510#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
10511 duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
10512
10513/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */
10514#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
10515 duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
10516
10517/* identifiers and environment handling */
10518#if 0 /*unused*/
10519DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
10520#endif
10521DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
10522DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
10523DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
10524DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
10525#if 0 /*unused*/
10526DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
10527#endif
10528DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
10529DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl);
10530DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
10531DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env);
10532DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff);
10533DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr,
10534 duk_hcompfunc *fun_temp,
10535 duk_hobject *outer_var_env,
10536 duk_hobject *outer_lex_env,
10537 duk_bool_t add_auto_proto);
10538
10539/* call handling */
10540DUK_INTERNAL_DECL void duk_native_stack_check(duk_hthread *thr);
10541DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags);
10542DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
10543DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
10544DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant);
10545#if defined(DUK_USE_VERBOSE_ERRORS)
10546DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_base, duk_tval *tv_key);
10547#endif
10548
10549/* bytecode execution */
10550DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
10551
10552#endif /* DUK_JS_H_INCLUDED */
10553/* #include duk_numconv.h */
10554#line 1 "duk_numconv.h"
10555/*
10556 * Number-to-string conversion. The semantics of these is very tightly
10557 * bound with the ECMAScript semantics required for call sites.
10558 */
10559
10560#if !defined(DUK_NUMCONV_H_INCLUDED)
10561#define DUK_NUMCONV_H_INCLUDED
10562
10563/* Output a specified number of digits instead of using the shortest
10564 * form. Used for toPrecision() and toFixed().
10565 */
10566#define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0)
10567
10568/* Force exponential format. Used for toExponential(). */
10569#define DUK_N2S_FLAG_FORCE_EXP (1U << 1)
10570
10571/* If number would need zero padding (for whole number part), use
10572 * exponential format instead. E.g. if input number is 12300, 3
10573 * digits are generated ("123"), output "1.23e+4" instead of "12300".
10574 * Used for toPrecision().
10575 */
10576#define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2)
10577
10578/* Digit count indicates number of fractions (i.e. an absolute
10579 * digit index instead of a relative one). Used together with
10580 * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
10581 */
10582#define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3)
10583
10584/*
10585 * String-to-number conversion
10586 */
10587
10588/* Maximum exponent value when parsing numbers. This is not strictly
10589 * compliant as there should be no upper limit, but as we parse the
10590 * exponent without a bigint, impose some limit. The limit should be
10591 * small enough that multiplying it (or limit-1 to be precise) won't
10592 * overflow signed 32-bit integer range. Exponent is only parsed with
10593 * radix 10, but with maximum radix (36) a safe limit is:
10594 * (10000000*36).toString(16) -> '15752a00'
10595 */
10596#define DUK_S2N_MAX_EXPONENT 10000000L
10597
10598/* Trim white space (= allow leading and trailing whitespace) */
10599#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0)
10600
10601/* Allow exponent */
10602#define DUK_S2N_FLAG_ALLOW_EXP (1U << 1)
10603
10604/* Allow trailing garbage (e.g. treat "123foo" as "123) */
10605#define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2)
10606
10607/* Allow leading plus sign */
10608#define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3)
10609
10610/* Allow leading minus sign */
10611#define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4)
10612
10613/* Allow 'Infinity' */
10614#define DUK_S2N_FLAG_ALLOW_INF (1U << 5)
10615
10616/* Allow fraction part */
10617#define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6)
10618
10619/* Allow naked fraction (e.g. ".123") */
10620#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7)
10621
10622/* Allow empty fraction (e.g. "123.") */
10623#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8)
10624
10625/* Allow empty string to be interpreted as 0 */
10626#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9)
10627
10628/* Allow leading zeroes (e.g. "0123" -> "123") */
10629#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10)
10630
10631/* Allow automatic detection of hex base ("0x" or "0X" prefix),
10632 * overrides radix argument and forces integer mode.
10633 */
10634#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11)
10635
10636/* Allow automatic detection of legacy octal base ("0n"),
10637 * overrides radix argument and forces integer mode.
10638 */
10639#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12)
10640
10641/* Allow automatic detection of ES2015 octal base ("0o123"),
10642 * overrides radix argument and forces integer mode.
10643 */
10644#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13)
10645
10646/* Allow automatic detection of ES2015 binary base ("0b10001"),
10647 * overrides radix argument and forces integer mode.
10648 */
10649#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14)
10650
10651/*
10652 * Prototypes
10653 */
10654
10655DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
10656DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags);
10657
10658#endif /* DUK_NUMCONV_H_INCLUDED */
10659/* #include duk_bi_protos.h */
10660#line 1 "duk_bi_protos.h"
10661/*
10662 * Prototypes for built-in functions not automatically covered by the
10663 * header declarations emitted by genbuiltins.py.
10664 */
10665
10666#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
10667#define DUK_BUILTIN_PROTOS_H_INCLUDED
10668
10669/* Buffer size needed for ISO 8601 formatting.
10670 * Accurate value is 32 + 1 for NUL termination:
10671 * >>> len('+123456-01-23T12:34:56.123+12:34')
10672 * 32
10673 * Include additional space to be safe.
10674 */
10675#define DUK_BI_DATE_ISO8601_BUFSIZE 40
10676
10677/* Helpers exposed for internal use */
10678DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags);
10679DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
10680DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
10681DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
10682DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
10683DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
10684/* Built-in providers */
10685#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
10686DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
10687#endif
10688#if defined(DUK_USE_DATE_NOW_TIME)
10689DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
10690#endif
10691#if defined(DUK_USE_DATE_NOW_WINDOWS)
10692DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
10693#endif
10694#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
10695DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
10696#endif
10697#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
10698DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
10699#endif
10700#if defined(DUK_USE_DATE_TZO_WINDOWS)
10701DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
10702#endif
10703#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
10704DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d);
10705#endif
10706#if defined(DUK_USE_DATE_PRS_STRPTIME)
10707DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str);
10708#endif
10709#if defined(DUK_USE_DATE_PRS_GETDATE)
10710DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str);
10711#endif
10712#if defined(DUK_USE_DATE_FMT_STRFTIME)
10713DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
10714#endif
10715
10716#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
10717DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
10718#endif
10719#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
10720DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
10721#endif
10722
10723DUK_INTERNAL_DECL
10724void duk_bi_json_parse_helper(duk_hthread *thr,
10725 duk_idx_t idx_value,
10726 duk_idx_t idx_reviver,
10727 duk_small_uint_t flags);
10728DUK_INTERNAL_DECL
10729void duk_bi_json_stringify_helper(duk_hthread *thr,
10730 duk_idx_t idx_value,
10731 duk_idx_t idx_replacer,
10732 duk_idx_t idx_space,
10733 duk_small_uint_t flags);
10734
10735DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
10736
10737#if defined(DUK_USE_ES6_PROXY)
10738DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
10739#endif
10740
10741#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
10742/* #include duk_selftest.h */
10743#line 1 "duk_selftest.h"
10744/*
10745 * Selftest code
10746 */
10747
10748#if !defined(DUK_SELFTEST_H_INCLUDED)
10749#define DUK_SELFTEST_H_INCLUDED
10750
10751#if defined(DUK_USE_SELF_TESTS)
10752DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
10753 duk_realloc_function realloc_func,
10754 duk_free_function free_func,
10755 void *udata);
10756#endif
10757
10758#endif /* DUK_SELFTEST_H_INCLUDED */
10759#line 76 "duk_internal.h"
10760
10761#endif /* DUK_INTERNAL_H_INCLUDED */
10762#line 10 "duk_replacements.c"
10763
10764#if defined(DUK_USE_COMPUTED_NAN)
10765DUK_INTERNAL double duk_computed_nan;
10766#endif
10767
10768#if defined(DUK_USE_COMPUTED_INFINITY)
10769DUK_INTERNAL double duk_computed_infinity;
10770#endif
10771
10772#if defined(DUK_USE_REPL_FPCLASSIFY)
10773DUK_INTERNAL int duk_repl_fpclassify(double x) {
10774 duk_double_union u;
10775 duk_uint_fast16_t expt;
10776 duk_small_int_t mzero;
10777
10778 u.d = x;
10779 expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
10780 if (expt > 0x0000UL && expt < 0x7ff0UL) {
10781 /* expt values [0x001,0x7fe] = normal */
10782 return DUK_FP_NORMAL;
10783 }
10784
10785 mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
10786 if (expt == 0x0000UL) {
10787 /* expt 0x000 is zero/subnormal */
10788 if (mzero) {
10789 return DUK_FP_ZERO;
10790 } else {
10791 return DUK_FP_SUBNORMAL;
10792 }
10793 } else {
10794 /* expt 0xfff is infinite/nan */
10795 if (mzero) {
10796 return DUK_FP_INFINITE;
10797 } else {
10798 return DUK_FP_NAN;
10799 }
10800 }
10801}
10802#endif
10803
10804#if defined(DUK_USE_REPL_SIGNBIT)
10805DUK_INTERNAL int duk_repl_signbit(double x) {
10806 duk_double_union u;
10807 u.d = x;
10808 return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
10809}
10810#endif
10811
10812#if defined(DUK_USE_REPL_ISFINITE)
10813DUK_INTERNAL int duk_repl_isfinite(double x) {
10814 int c = DUK_FPCLASSIFY(x);
10815 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
10816 return 0;
10817 } else {
10818 return 1;
10819 }
10820}
10821#endif
10822
10823#if defined(DUK_USE_REPL_ISNAN)
10824DUK_INTERNAL int duk_repl_isnan(double x) {
10825 int c = DUK_FPCLASSIFY(x);
10826 return (c == DUK_FP_NAN);
10827}
10828#endif
10829
10830#if defined(DUK_USE_REPL_ISINF)
10831DUK_INTERNAL int duk_repl_isinf(double x) {
10832 int c = DUK_FPCLASSIFY(x);
10833 return (c == DUK_FP_INFINITE);
10834}
10835#endif
10836#line 1 "duk_debug_macros.c"
10837/*
10838 * Debugging macro calls.
10839 */
10840
10841/* #include duk_internal.h -> already included */
10842
10843#if defined(DUK_USE_DEBUG)
10844
10845/*
10846 * Debugging enabled
10847 */
10848
10849#include <stdio.h>
10850#include <stdlib.h>
10851#include <stdarg.h>
10852
10853#if !defined(DUK_USE_DEBUG_WRITE)
10854#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
10855#endif
10856
10857#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
10858
10859#if defined(DUK_USE_VARIADIC_MACROS)
10860
10861DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
10862 va_list ap;
10863 long arg_level;
10864 const char *arg_file;
10865 long arg_line;
10866 const char *arg_func;
10867 const char *arg_msg;
10868 char buf[DUK__DEBUG_BUFSIZE];
10869
10870 va_start(ap, fmt);
10871
10872 duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
10873 duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
10874
10875 arg_level = (long) level;
10876 arg_file = (const char *) file;
10877 arg_line = (long) line;
10878 arg_func = (const char *) func;
10879 arg_msg = (const char *) buf;
10880 DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
10881
10882 va_end(ap);
10883}
10884
10885#else /* DUK_USE_VARIADIC_MACROS */
10886
10887DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
10888DUK_INTERNAL duk_int_t duk_debug_line_stash;
10889DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
10890DUK_INTERNAL duk_int_t duk_debug_level_stash;
10891
10892DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
10893 va_list ap;
10894 long arg_level;
10895 const char *arg_file;
10896 long arg_line;
10897 const char *arg_func;
10898 const char *arg_msg;
10899 char buf[DUK__DEBUG_BUFSIZE];
10900
10901 va_start(ap, fmt);
10902
10903 duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
10904 duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
10905
10906 arg_level = (long) duk_debug_level_stash;
10907 arg_file = (const char *) duk_debug_file_stash;
10908 arg_line = (long) duk_debug_line_stash;
10909 arg_func = (const char *) duk_debug_func_stash;
10910 arg_msg = (const char *) buf;
10911 DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
10912
10913 va_end(ap);
10914}
10915
10916#endif /* DUK_USE_VARIADIC_MACROS */
10917
10918#else /* DUK_USE_DEBUG */
10919
10920/*
10921 * Debugging disabled
10922 */
10923
10924#endif /* DUK_USE_DEBUG */
10925
10926/* automatic undefs */
10927#undef DUK__DEBUG_BUFSIZE
10928#line 1 "duk_builtins.c"
10929/*
10930 * Automatically generated by genbuiltins.py, do not edit!
10931 */
10932
10933/* #include duk_internal.h -> already included */
10934
10935#if defined(DUK_USE_ASSERTIONS)
10936#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/
10937#else
10938#define DUK__REFCINIT(refc) (refc) /*actual*/
10939#endif
10940
10941#if defined(DUK_USE_ROM_STRINGS)
10942#error ROM support not enabled, rerun configure.py with --rom-support
10943#else /* DUK_USE_ROM_STRINGS */
10944DUK_INTERNAL const duk_uint8_t duk_strings_data[972] = {
1094579,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
1094635,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
10947129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
10948140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
10949193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
10950196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
10951196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
10952229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
10953183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
10954184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
10955178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
1095632,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
10957113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
10958119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
10959101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
10960226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
1096152,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
1096267,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
10963249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
10964186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
1096532,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
10966231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11,
10967151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92,
10968112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74,
10969113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39,
10970201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78,
10971214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240,
10972242,16,96,152,12,26,20,164,137,150,70,154,103,28,137,50,202,96,18,132,241,
1097341,104,105,56,218,48,36,138,183,57,56,128,68,24,38,2,52,12,34,10,133,147,
10974141,3,8,119,185,13,153,34,125,206,76,17,49,38,93,206,52,151,154,119,56,28,
1097576,130,112,200,141,206,21,209,96,23,35,238,114,160,139,0,243,238,114,78,
10976164,68,68,110,113,226,210,90,26,66,110,113,128,121,247,57,80,68,141,170,
10977183,56,84,52,11,70,73,19,110,114,160,93,8,113,57,143,66,200,84,53,244,154,
1097873,24,240,81,32,38,68,18,49,228,207,23,88,100,109,70,114,92,193,4,137,173,
10979168,36,220,73,19,247,247,182,168,209,144,187,223,58,156,104,79,190,183,127,
10980123,105,160,110,247,206,167,26,19,239,173,223,222,218,67,75,189,243,169,
10981198,132,251,235,183,247,182,154,134,151,123,231,83,141,9,247,215,111,239,
10982109,22,141,22,247,206,167,26,19,239,172,223,218,45,26,47,157,78,52,39,223,
1098374,24,144,10,32,129,34,20,64,152,142,129,57,179,67,104,68,12,129,161,140,
1098472,156,100,40,40,185,152,100,89,38,65,13,196,34,228,67,149,13,2,215,129,
10985149,209,65,104,209,77,14,104,144,81,33,170,67,101,48,52,68,113,70,210,88,
10986209,36,233,22,154,86,68,196,114,76,232,145,102,120,186,195,156,112,105,225,
10987228,113,71,80,68,162,115,101,50,85,200,25,108,116,44,132,178,38,114,137,96,
10988148,136,70,209,134,37,222,232,204,228,188,200,209,200,200,99,221,25,150,84,
10989121,34,70,209,107,36,227,66,20,160,92,136,164,49,235,35,8,217,201,40,108,
10990201,18,128,68,26,201,51,188,2,80,12,67,190,40,168,38,68,190,46,153,5,50,12,
10991207,160,86,129,26,83,4,208,34,225,4,88,192,
10992};
10993#endif /* DUK_USE_ROM_STRINGS */
10994
10995#if defined(DUK_USE_ROM_OBJECTS)
10996#error ROM support not enabled, rerun configure.py with --rom-support
10997#else /* DUK_USE_ROM_OBJECTS */
10998/* native functions: 185 */
10999DUK_INTERNAL const duk_c_function duk_bi_native_functions[185] = {
11000 NULL,
11001 duk_bi_array_constructor,
11002 duk_bi_array_constructor_is_array,
11003 duk_bi_array_prototype_concat,
11004 duk_bi_array_prototype_indexof_shared,
11005 duk_bi_array_prototype_iter_shared,
11006 duk_bi_array_prototype_join_shared,
11007 duk_bi_array_prototype_pop,
11008 duk_bi_array_prototype_push,
11009 duk_bi_array_prototype_reduce_shared,
11010 duk_bi_array_prototype_reverse,
11011 duk_bi_array_prototype_shift,
11012 duk_bi_array_prototype_slice,
11013 duk_bi_array_prototype_sort,
11014 duk_bi_array_prototype_splice,
11015 duk_bi_array_prototype_to_string,
11016 duk_bi_array_prototype_unshift,
11017 duk_bi_arraybuffer_constructor,
11018 duk_bi_arraybuffer_isview,
11019 duk_bi_boolean_constructor,
11020 duk_bi_boolean_prototype_tostring_shared,
11021 duk_bi_buffer_compare_shared,
11022 duk_bi_buffer_readfield,
11023 duk_bi_buffer_slice_shared,
11024 duk_bi_buffer_writefield,
11025 duk_bi_cbor_decode,
11026 duk_bi_cbor_encode,
11027 duk_bi_dataview_constructor,
11028 duk_bi_date_constructor,
11029 duk_bi_date_constructor_now,
11030 duk_bi_date_constructor_parse,
11031 duk_bi_date_constructor_utc,
11032 duk_bi_date_prototype_get_shared,
11033 duk_bi_date_prototype_get_timezone_offset,
11034 duk_bi_date_prototype_set_shared,
11035 duk_bi_date_prototype_set_time,
11036 duk_bi_date_prototype_to_json,
11037 duk_bi_date_prototype_toprimitive,
11038 duk_bi_date_prototype_tostring_shared,
11039 duk_bi_date_prototype_value_of,
11040 duk_bi_duktape_object_act,
11041 duk_bi_duktape_object_compact,
11042 duk_bi_duktape_object_dec,
11043 duk_bi_duktape_object_enc,
11044 duk_bi_duktape_object_fin,
11045 duk_bi_duktape_object_gc,
11046 duk_bi_duktape_object_info,
11047 duk_bi_error_constructor_shared,
11048 duk_bi_error_prototype_filename_getter,
11049 duk_bi_error_prototype_filename_setter,
11050 duk_bi_error_prototype_linenumber_getter,
11051 duk_bi_error_prototype_linenumber_setter,
11052 duk_bi_error_prototype_stack_getter,
11053 duk_bi_error_prototype_stack_setter,
11054 duk_bi_error_prototype_to_string,
11055 duk_bi_function_constructor,
11056 duk_bi_function_prototype,
11057 duk_bi_function_prototype_apply,
11058 duk_bi_function_prototype_bind,
11059 duk_bi_function_prototype_call,
11060 duk_bi_function_prototype_hasinstance,
11061 duk_bi_function_prototype_to_string,
11062 duk_bi_global_object_decode_uri,
11063 duk_bi_global_object_decode_uri_component,
11064 duk_bi_global_object_encode_uri,
11065 duk_bi_global_object_encode_uri_component,
11066 duk_bi_global_object_escape,
11067 duk_bi_global_object_eval,
11068 duk_bi_global_object_is_finite,
11069 duk_bi_global_object_is_nan,
11070 duk_bi_global_object_parse_float,
11071 duk_bi_global_object_parse_int,
11072 duk_bi_global_object_unescape,
11073 duk_bi_json_object_parse,
11074 duk_bi_json_object_stringify,
11075 duk_bi_math_object_clz32,
11076 duk_bi_math_object_hypot,
11077 duk_bi_math_object_imul,
11078 duk_bi_math_object_max,
11079 duk_bi_math_object_min,
11080 duk_bi_math_object_onearg_shared,
11081 duk_bi_math_object_random,
11082 duk_bi_math_object_sign,
11083 duk_bi_math_object_twoarg_shared,
11084 duk_bi_native_function_length,
11085 duk_bi_native_function_name,
11086 duk_bi_nodejs_buffer_byte_length,
11087 duk_bi_nodejs_buffer_concat,
11088 duk_bi_nodejs_buffer_constructor,
11089 duk_bi_nodejs_buffer_copy,
11090 duk_bi_nodejs_buffer_fill,
11091 duk_bi_nodejs_buffer_is_buffer,
11092 duk_bi_nodejs_buffer_is_encoding,
11093 duk_bi_nodejs_buffer_tojson,
11094 duk_bi_nodejs_buffer_tostring,
11095 duk_bi_nodejs_buffer_write,
11096 duk_bi_number_check_shared,
11097 duk_bi_number_constructor,
11098 duk_bi_number_prototype_to_exponential,
11099 duk_bi_number_prototype_to_fixed,
11100 duk_bi_number_prototype_to_locale_string,
11101 duk_bi_number_prototype_to_precision,
11102 duk_bi_number_prototype_to_string,
11103 duk_bi_number_prototype_value_of,
11104 duk_bi_object_constructor,
11105 duk_bi_object_constructor_assign,
11106 duk_bi_object_constructor_create,
11107 duk_bi_object_constructor_define_properties,
11108 duk_bi_object_constructor_define_property,
11109 duk_bi_object_constructor_get_own_property_descriptor,
11110 duk_bi_object_constructor_is,
11111 duk_bi_object_constructor_is_extensible,
11112 duk_bi_object_constructor_is_sealed_frozen_shared,
11113 duk_bi_object_constructor_keys_shared,
11114 duk_bi_object_constructor_prevent_extensions,
11115 duk_bi_object_constructor_seal_freeze_shared,
11116 duk_bi_object_getprototype_shared,
11117 duk_bi_object_prototype_defineaccessor,
11118 duk_bi_object_prototype_has_own_property,
11119 duk_bi_object_prototype_is_prototype_of,
11120 duk_bi_object_prototype_lookupaccessor,
11121 duk_bi_object_prototype_property_is_enumerable,
11122 duk_bi_object_prototype_to_locale_string,
11123 duk_bi_object_prototype_to_string,
11124 duk_bi_object_prototype_value_of,
11125 duk_bi_object_setprototype_shared,
11126 duk_bi_performance_now,
11127 duk_bi_pointer_constructor,
11128 duk_bi_pointer_prototype_tostring_shared,
11129 duk_bi_proxy_constructor,
11130 duk_bi_reflect_apply,
11131 duk_bi_reflect_construct,
11132 duk_bi_reflect_object_delete_property,
11133 duk_bi_reflect_object_get,
11134 duk_bi_reflect_object_has,
11135 duk_bi_reflect_object_set,
11136 duk_bi_regexp_constructor,
11137 duk_bi_regexp_prototype_exec,
11138 duk_bi_regexp_prototype_flags,
11139 duk_bi_regexp_prototype_shared_getter,
11140 duk_bi_regexp_prototype_test,
11141 duk_bi_regexp_prototype_tostring,
11142 duk_bi_string_constructor,
11143 duk_bi_string_constructor_from_char_code,
11144 duk_bi_string_constructor_from_code_point,
11145 duk_bi_string_prototype_caseconv_shared,
11146 duk_bi_string_prototype_char_at,
11147 duk_bi_string_prototype_char_code_at,
11148 duk_bi_string_prototype_concat,
11149 duk_bi_string_prototype_includes,
11150 duk_bi_string_prototype_indexof_shared,
11151 duk_bi_string_prototype_locale_compare,
11152 duk_bi_string_prototype_match,
11153 duk_bi_string_prototype_repeat,
11154 duk_bi_string_prototype_replace,
11155 duk_bi_string_prototype_search,
11156 duk_bi_string_prototype_slice,
11157 duk_bi_string_prototype_split,
11158 duk_bi_string_prototype_startswith_endswith,
11159 duk_bi_string_prototype_substr,
11160 duk_bi_string_prototype_substring,
11161 duk_bi_string_prototype_to_string,
11162 duk_bi_string_prototype_trim,
11163 duk_bi_symbol_constructor_shared,
11164 duk_bi_symbol_key_for,
11165 duk_bi_symbol_toprimitive,
11166 duk_bi_symbol_tostring_shared,
11167 duk_bi_textdecoder_constructor,
11168 duk_bi_textdecoder_prototype_decode,
11169 duk_bi_textdecoder_prototype_shared_getter,
11170 duk_bi_textencoder_constructor,
11171 duk_bi_textencoder_prototype_encode,
11172 duk_bi_textencoder_prototype_encoding_getter,
11173 duk_bi_thread_constructor,
11174 duk_bi_thread_current,
11175 duk_bi_thread_resume,
11176 duk_bi_thread_yield,
11177 duk_bi_type_error_thrower,
11178 duk_bi_typedarray_buffer_getter,
11179 duk_bi_typedarray_bytelength_getter,
11180 duk_bi_typedarray_byteoffset_getter,
11181 duk_bi_typedarray_constructor,
11182 duk_bi_typedarray_set,
11183 duk_bi_uint8array_allocplain,
11184 duk_bi_uint8array_plainof,
11185};
11186#if defined(DUK_USE_DOUBLE_LE)
11187DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
11188144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
11189124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
11190167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
1119164,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
11192142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
11193242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
111941,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
1119533,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
11196198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
1119710,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
1119853,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
1119984,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
11200109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
1120111,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
11202145,153,136,0,0,0,0,0,0,31,15,249,152,0,0,0,0,0,0,30,15,249,120,144,13,96,
11203155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23,
11204194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
11205137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
1120636,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
11207209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
11208144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
11209122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
11210136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
11211195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
1121217,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
112132,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
1121435,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
11215174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
112160,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
1121773,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
1121889,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
11219144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
1122078,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
11221196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
11222132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
11223162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
11224160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
11225151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
11226113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
11227129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
11228168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
11229153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
1123036,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
11231203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
11232136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
11233207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
1123437,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
1123544,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
11236231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
1123730,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
11238196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
1123935,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
1124034,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
11241120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
1124268,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
11243228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
1124418,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
11245249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
11246102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
112479,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
11248255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
1124957,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
11250130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
1125111,161,32,127,255,255,255,255,255,247,191,137,235,16,221,170,129,116,36,0,
1125216,0,0,0,0,0,0,12,196,0,0,0,0,0,0,15,135,242,61,123,164,137,162,164,218,67,
1125374,134,162,120,128,0,0,0,0,0,1,224,254,71,173,33,129,52,84,155,72,105,80,
11254212,79,16,0,0,0,0,0,0,60,63,195,244,143,146,22,230,192,0,0,0,0,0,0,176,60,
1125533,214,2,251,82,1,73,180,134,204,134,36,96,127,255,255,255,255,255,159,161,
11256144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,255,255,255,255,207,
11257240,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,
1125892,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
11259194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0,
112600,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
1126118,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
112625,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0,0,
112630,0,0,248,127,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155,
11264185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
11265130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
11266197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
1126712,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
11268218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
1126998,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
11270250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
1127140,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
1127249,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
1127356,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
11274173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
11275168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
1127618,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
11277210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
1127872,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
1127972,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
11280186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
1128150,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
1128274,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
11283186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
11284162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
1128555,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
1128648,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
1128782,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
11288144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
11289221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
11290105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
11291137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
1129223,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
1129319,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
1129472,115,96,0,0,0,0,0,15,106,32,91,60,165,195,201,194,8,134,149,216,162,0,
11295192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
11296195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
112971,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
1129836,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
112990,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
11300102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
1130120,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
11302216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
1130381,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
11304166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
1130520,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
1130668,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
11307159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
1130867,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
11309173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
11310140,35,103,0,0,0,0,0,0,3,192,252,206,25,228,35,208,226,100,150,211,201,29,
11311162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,25,244,35,208,226,100,150,211,
11312201,29,162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,26,4,35,208,226,100,150,
11313211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,20,35,208,226,100,
11314150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,36,35,208,226,
11315100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,52,35,208,
11316226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,68,35,
11317208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,84,
1131835,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,129,0,195,
11319154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
1132025,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
11321235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
11322196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
11323200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
11324213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
11325183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
11326221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
1132731,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
1132818,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
1132959,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
1133039,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
1133173,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
1133261,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
1133367,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
11334167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
1133568,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
11336193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
11337178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
11338157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
1133981,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
11340133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
1134122,209,68,201,187,129,4,2,8,3,132,64,60,36,6,149,113,72,176,171,240,84,0,
11342157,91,116,116,32,11,42,218,221,216,181,129,32,3,234,219,165,3,188,231,235,
11343249,8,187,152,252,47,86,227,105,18,7,244,17,91,42,56,175,185,248,110,173,
11344198,209,208,36,0,238,82,97,87,188,189,179,240,93,122,32,12,22,162,42,125,
11345144,132,160,7,236,161,25,232,237,105,64,205,59,127,102,158,160,230,63,11,
11346217,66,51,210,129,154,118,254,205,61,65,236,127,171,197,34,168,48,6,90,194,
113471,0,39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,
1134865,6,51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,
1134980,0,201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,
1135069,234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,
11351165,1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,
11352107,64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,
11353132,103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,
11354145,52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,
11355104,146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,
1135656,18,52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,
1135747,129,6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,
1135815,155,163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,
1135936,3,17,46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,
11360248,75,204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,
11361206,9,113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,
11362178,66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,
1136338,232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,
1136438,3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,
11365202,160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,
113660,0,179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,
11367181,192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,
11368121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,153,188,56,132,122,28,76,
11369146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23,
1137030,176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,
11371153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,120,145,8,244,
1137256,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,161,8,
11373244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,177,
113748,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,120,
11375193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,
11376120,209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,
1137751,120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32,
1137864,32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,
11379137,112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,
1138034,74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,
113818,35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,
11382117,96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,
1138332,148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,
11384238,2,3,107,173,218,3,192,
11385};
11386#elif defined(DUK_USE_DOUBLE_BE)
11387DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
11388144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
11389124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
11390167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
1139164,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
11392142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
11393242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
113941,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
1139533,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
11396198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
1139710,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
1139853,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
1139984,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
11400109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
1140111,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
11402145,153,136,15,255,0,0,0,0,0,0,25,152,15,254,0,0,0,0,0,0,25,120,144,13,96,
11403155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23,
11404194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
11405137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
1140636,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
11407209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
11408144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
11409122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
11410136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
11411195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
1141217,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
114132,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
1141435,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
11415174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
114160,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
1141773,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
1141889,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
11419144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
1142078,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
11421196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
11422132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
11423162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
11424160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
11425151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
11426113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
11427129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
11428168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
11429153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
1143036,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
11431203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
11432136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
11433207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
1143437,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
1143544,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
11436231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
1143730,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
11438196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
1143935,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
1144034,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
11441120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
1144268,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
11443228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
1144418,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
11445249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
11446102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
114479,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
11448255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
1144957,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
11450130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
1145111,161,32,63,247,255,255,255,255,255,255,137,235,16,221,170,129,116,36,0,0,
114520,0,0,0,0,0,28,196,7,255,128,0,0,0,0,0,2,61,123,164,137,162,164,218,67,74,
11453134,162,120,128,255,224,0,0,0,0,0,0,71,173,33,129,52,84,155,72,105,80,212,
1145479,16,63,252,0,0,0,0,0,0,3,244,143,146,22,230,192,60,176,0,0,0,0,0,0,33,
11455214,2,251,82,1,73,180,134,204,134,36,96,33,159,255,255,255,255,255,255,144,
11456235,16,221,169,0,164,218,67,102,67,18,48,48,207,255,255,255,255,255,255,
11457196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,92,
1145842,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
11459194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0,
114600,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
1146118,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
114625,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,127,
11463248,0,0,0,0,0,0,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155,
11464185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
11465130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
11466197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
1146712,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
11468218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
1146998,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
11470250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
1147140,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
1147249,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
1147356,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
11474173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
11475168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
1147618,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
11477210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
1147872,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
1147972,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
11480186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
1148150,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
1148274,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
11483186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
11484162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
1148555,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
1148648,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
1148782,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
11488144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
11489221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
11490105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
11491137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
1149223,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
1149319,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
1149472,115,96,32,106,15,0,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
11495192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
11496195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
114971,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
1149836,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
114990,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
11500102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
1150120,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
11502216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
1150381,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
11504166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
1150520,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
1150668,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
11507159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
1150867,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
11509173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
11510140,35,103,0,255,192,0,0,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29,
11511162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,25,244,35,208,226,100,150,211,
11512201,29,162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,26,4,35,208,226,100,150,
11513211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,20,35,208,226,100,
11514150,211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,36,35,208,226,
11515100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,52,35,208,
11516226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,68,35,
11517208,226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,84,
1151835,208,226,100,150,211,201,29,162,44,140,35,103,1,0,128,0,0,0,0,0,0,195,
11519154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
1152025,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
11521235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
11522196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
11523200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
11524213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
11525183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
11526221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
1152731,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
1152818,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
1152959,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
1153039,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
1153173,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
1153261,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
1153367,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
11534167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
1153568,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
11536193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
11537178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
11538157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
1153981,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
11540133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
1154122,209,68,201,187,129,4,2,8,3,132,64,60,36,4,0,91,240,168,177,69,118,144,
11542157,91,116,116,32,32,1,53,216,221,218,170,139,3,234,219,165,0,255,152,185,
1154311,251,232,231,188,47,86,227,105,18,1,255,184,170,59,41,92,23,240,110,173,
11544198,209,208,36,3,253,188,183,177,82,110,80,224,93,122,32,32,4,144,253,170,
1154534,22,140,7,236,161,25,232,237,105,64,63,230,160,158,102,127,59,205,11,217,
1154666,51,210,128,127,237,65,60,204,254,119,155,171,197,34,168,48,6,90,194,1,0,
1154739,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6,
1154851,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0,
11549201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69,
11550234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165,
115511,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107,
1155264,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132,
11553103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145,
1155452,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104,
11555146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18,
1155652,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129,
115576,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,
11558163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17,
1155946,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75,
11560204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9,
11561113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178,
1156266,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38,
11563232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38,
115643,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202,
11565160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0,
11566179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181,
11567192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121,
1156835,180,69,145,132,108,224,31,248,0,0,0,0,0,0,25,188,56,132,122,28,76,146,
11569218,121,35,180,69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30,
11570176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153,
1157137,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,120,145,8,244,56,
11572153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,161,8,244,
1157356,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,177,8,
11574244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120,193,
115758,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120,
11576209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,
11577120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0,
1157832,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137,
11579112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34,
1158074,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8,
1158135,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117,
1158296,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32,
11583148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2,
115843,107,173,218,3,192,
11585};
11586#elif defined(DUK_USE_DOUBLE_ME)
11587DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
11588144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
11589124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
11590167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
1159164,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
11592142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
11593242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
115941,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
1159533,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
11596198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
1159710,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
1159853,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
1159984,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
11600109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
1160111,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
11602145,153,136,0,0,31,15,224,0,0,0,25,152,0,0,30,15,224,0,0,0,25,120,144,13,
1160396,155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,
1160423,194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
11605137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
1160636,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
11607209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
11608144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
11609122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
11610136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
11611195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
1161217,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
116132,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
1161435,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
11615174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
116160,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
1161773,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
1161889,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
11619144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
1162078,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
11621196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
11622132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
11623162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
11624160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
11625151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
11626113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
11627129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
11628168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
11629153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
1163036,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
11631203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
11632136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
11633207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
1163437,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
1163544,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
11636231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
1163730,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
11638196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
1163935,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
1164034,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
11641120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
1164268,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
11643228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
1164418,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
11645249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
11646102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
116479,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
11648255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
1164957,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
11650130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
1165111,161,32,127,255,247,191,255,255,255,255,137,235,16,221,170,129,116,36,0,
116520,0,0,0,16,0,0,12,196,0,0,15,135,240,0,0,0,2,61,123,164,137,162,164,218,67,
1165374,134,162,120,128,0,1,224,254,0,0,0,0,71,173,33,129,52,84,155,72,105,80,
11654212,79,16,0,0,60,63,192,0,0,0,3,244,143,146,22,230,192,0,0,176,60,0,0,0,0,
1165533,214,2,251,82,1,73,180,134,204,134,36,96,127,255,159,161,255,255,255,255,
11656144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,207,240,255,255,255,
11657255,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,
1165892,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
11659194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0,
116600,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
1166118,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
116625,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0,
11663248,127,0,0,0,0,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155,
11664185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
11665130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
11666197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
1166712,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
11668218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
1166998,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
11670250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
1167140,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
1167249,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
1167356,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
11674173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
11675168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
1167618,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
11677210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
1167872,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
1167972,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
11680186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
1168150,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
1168274,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
11683186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
11684162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
1168555,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
1168648,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
1168782,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
11688144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
11689221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
11690105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
11691137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
1169223,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
1169319,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
1169472,115,96,0,15,106,32,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
11695192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
11696195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
116971,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
1169836,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
116990,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
11700102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
1170120,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179,
11702216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
1170381,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
11704166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
1170520,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
1170668,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
11707159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
1170867,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
11709173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
11710140,35,103,0,0,3,192,252,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29,
11711162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,25,244,35,208,226,100,150,211,
11712201,29,162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,26,4,35,208,226,100,150,
11713211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,20,35,208,226,100,
11714150,211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,36,35,208,226,
11715100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,52,35,208,
11716226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,68,35,
11717208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,84,
1171835,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,129,0,0,0,0,0,195,
11719154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
1172025,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
11721235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
11722196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
11723200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
11724213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
11725183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
11726221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
1172731,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
1172818,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
1172959,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
1173039,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
1173173,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
1173261,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
1173367,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
11734167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
1173568,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
11736193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
11737178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
11738157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
1173981,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
11740133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
1174122,209,68,201,187,129,4,2,8,3,132,64,60,36,0,171,240,84,6,149,113,72,176,
11742157,91,116,116,32,88,181,129,32,11,42,218,221,131,234,219,165,1,8,187,152,
11743255,188,231,235,248,47,86,227,105,18,2,56,175,185,255,244,17,91,40,110,173,
11744198,209,208,36,7,188,189,179,240,238,82,97,80,93,122,32,125,144,132,160,12,
1174522,162,42,7,236,161,25,232,237,105,64,158,160,230,63,205,59,127,102,11,217,
1174666,51,210,129,61,65,236,127,154,118,254,205,171,197,34,168,48,6,90,194,1,0,
1174739,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6,
1174851,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0,
11749201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69,
11750234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165,
117511,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107,
1175264,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132,
11753103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145,
1175452,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104,
11755146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18,
1175652,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129,
117576,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,
11758163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17,
1175946,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75,
11760204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9,
11761113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178,
1176266,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38,
11763232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38,
117643,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202,
11765160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0,
11766179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181,
11767192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121,
1176835,180,69,145,132,108,224,0,0,120,31,128,0,0,0,25,188,56,132,122,28,76,146,
11769218,121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30,
11770176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153,
1177137,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,120,145,8,244,56,
11772153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,161,8,244,
1177356,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,177,8,
11774244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120,193,
117758,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120,
11776209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,
11777120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0,
1177832,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137,
11779112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34,
1178074,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8,
1178135,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117,
1178296,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32,
11783148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2,
117843,107,173,218,3,192,
11785};
11786#else
11787#error invalid endianness defines
11788#endif
11789#endif /* DUK_USE_ROM_OBJECTS */
11790
11791/* automatic undefs */
11792#undef DUK__REFCINIT
11793#line 1 "duk_error_macros.c"
11794/*
11795 * Error and fatal handling.
11796 */
11797
11798/* #include duk_internal.h -> already included */
11799
11800#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
11801
11802#if defined(DUK_USE_VERBOSE_ERRORS)
11803
11804DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
11805 va_list ap;
11806 char msg[DUK__ERRFMT_BUFSIZE];
11807 va_start(ap, fmt);
11808 (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
11809 msg[sizeof(msg) - 1] = (char) 0;
11810 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
11811 va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
11812}
11813
11814DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
11815 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
11816}
11817
11818#else /* DUK_USE_VERBOSE_ERRORS */
11819
11820DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
11821 duk_err_create_and_throw(thr, code);
11822}
11823
11824#endif /* DUK_USE_VERBOSE_ERRORS */
11825
11826/*
11827 * Error throwing helpers
11828 */
11829
11830#if defined(DUK_USE_VERBOSE_ERRORS)
11831#if defined(DUK_USE_PARANOID_ERRORS)
11832DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
11833 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
11834 expect_name, duk_get_type_name(thr, idx), (long) idx);
11835}
11836#else
11837DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
11838 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
11839 expect_name, duk_push_string_readable(thr, idx), (long) idx);
11840}
11841#endif
11842DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11843 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
11844}
11845DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11846 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
11847}
11848DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
11849 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
11850}
11851DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
11852 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
11853}
11854DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
11855 DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
11856}
11857DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11858 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
11859}
11860DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11861 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
11862}
11863DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11864 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
11865}
11866DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11867 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
11868}
11869#else
11870/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
11871 * when non-verbose errors are used.
11872 */
11873
11874DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
11875DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
11876 DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
11877}
11878DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
11879 duk__err_shared(thr, DUK_ERR_ERROR);
11880}
11881DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) {
11882 duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
11883}
11884DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) {
11885 duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
11886}
11887DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) {
11888 duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
11889}
11890DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) {
11891 duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
11892}
11893DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) {
11894 duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
11895}
11896DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) {
11897 duk__err_shared(thr, DUK_ERR_URI_ERROR);
11898}
11899#endif
11900
11901/*
11902 * Default fatal error handler
11903 */
11904
11905DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) {
11906 DUK_UNREF(udata);
11907 DUK_UNREF(msg);
11908
11909 msg = msg ? msg : "NULL";
11910
11911#if defined(DUK_USE_FATAL_HANDLER)
11912 /* duk_config.h provided a custom default fatal handler. */
11913 DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg));
11914 DUK_USE_FATAL_HANDLER(udata, msg);
11915#elif defined(DUK_USE_CPP_EXCEPTIONS)
11916 /* With C++ use a duk_fatal_exception which user code can catch in
11917 * a natural way.
11918 */
11919 DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s", msg));
11920 throw duk_fatal_exception(msg);
11921#else
11922 /* Default behavior is to abort() on error. There's no printout
11923 * which makes this awkward, so it's always recommended to use an
11924 * explicit fatal error handler.
11925 *
11926 * ====================================================================
11927 * NOTE: If you are seeing this, you are most likely dealing with an
11928 * uncaught error. You should provide a fatal error handler in Duktape
11929 * heap creation, and should consider using a protected call as your
11930 * first call into an empty Duktape context to properly handle errors.
11931 * See:
11932 * - http://duktape.org/guide.html#error-handling
11933 * - http://wiki.duktape.org/HowtoFatalErrors.html
11934 * - http://duktape.org/api.html#taglist-protected
11935 * ====================================================================
11936 */
11937 DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg));
11938 DUK_ABORT();
11939#endif
11940
11941 DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
11942 for (;;) {
11943 /* Loop forever to ensure we don't return. */
11944 }
11945}
11946
11947/* automatic undefs */
11948#undef DUK__ERRFMT_BUFSIZE
11949#line 1 "duk_unicode_support.c"
11950/*
11951 * Various Unicode help functions for character classification predicates,
11952 * case conversion, decoding, etc.
11953 */
11954
11955/* #include duk_internal.h -> already included */
11956
11957/*
11958 * Fast path tables
11959 */
11960
11961#if defined(DUK_USE_IDCHAR_FASTPATH)
11962DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
11963 /* 0: not IdentifierStart or IdentifierPart
11964 * 1: IdentifierStart and IdentifierPart
11965 * -1: IdentifierPart only
11966 */
11967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */
11968 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */
11969 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */
11970 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */
11971 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */
11972 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */
11973 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */
11974 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */
11975};
11976#endif
11977
11978/*
11979 * XUTF-8 and CESU-8 encoding/decoding
11980 */
11981
11982DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
11983 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
11984 if (x < 0x80UL) {
11985 /* 7 bits */
11986 return 1;
11987 } else if (x < 0x800UL) {
11988 /* 11 bits */
11989 return 2;
11990 } else if (x < 0x10000UL) {
11991 /* 16 bits */
11992 return 3;
11993 } else if (x < 0x200000UL) {
11994 /* 21 bits */
11995 return 4;
11996 } else if (x < 0x4000000UL) {
11997 /* 26 bits */
11998 return 5;
11999 } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
12000 /* 31 bits */
12001 return 6;
12002 } else {
12003 /* 36 bits */
12004 return 7;
12005 }
12006}
12007
12008#if defined(DUK_USE_ASSERTIONS)
12009DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
12010 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
12011 if (x < 0x80UL) {
12012 /* 7 bits */
12013 return 1;
12014 } else if (x < 0x800UL) {
12015 /* 11 bits */
12016 return 2;
12017 } else if (x < 0x10000UL) {
12018 /* 16 bits */
12019 return 3;
12020 } else {
12021 /* Encoded as surrogate pair, each encoding to 3 bytes for
12022 * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes
12023 * too, see duk_unicode_encode_cesu8().
12024 */
12025 return 3 + 3;
12026 }
12027}
12028#endif /* DUK_USE_ASSERTIONS */
12029
12030DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
12031 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
12032};
12033
12034/* Encode to extended UTF-8; 'out' must have space for at least
12035 * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any
12036 * 32-bit (unsigned) codepoint.
12037 */
12038DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
12039 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
12040 duk_small_int_t len;
12041 duk_uint8_t marker;
12042 duk_small_int_t i;
12043
12044 len = duk_unicode_get_xutf8_length(cp);
12045 DUK_ASSERT(len > 0);
12046
12047 marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */
12048
12049 i = len;
12050 DUK_ASSERT(i > 0);
12051 do {
12052 i--;
12053 if (i > 0) {
12054 out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
12055 x >>= 6;
12056 } else {
12057 /* Note: masking of 'x' is not necessary because of
12058 * range check and shifting -> no bits overlapping
12059 * the marker should be set.
12060 */
12061 out[0] = (duk_uint8_t) (marker + x);
12062 }
12063 } while (i > 0);
12064
12065 return len;
12066}
12067
12068/* Encode to CESU-8; 'out' must have space for at least
12069 * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
12070 * will encode to garbage but won't overwrite the output buffer.
12071 */
12072DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
12073 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
12074 duk_small_int_t len;
12075
12076 if (x < 0x80UL) {
12077 out[0] = (duk_uint8_t) x;
12078 len = 1;
12079 } else if (x < 0x800UL) {
12080 out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
12081 out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
12082 len = 2;
12083 } else if (x < 0x10000UL) {
12084 /* surrogate pairs get encoded here */
12085 out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
12086 out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
12087 out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
12088 len = 3;
12089 } else {
12090 /*
12091 * Unicode codepoints above U+FFFF are encoded as surrogate
12092 * pairs here. This ensures that all CESU-8 codepoints are
12093 * 16-bit values as expected in ECMAScript. The surrogate
12094 * pairs always get a 3-byte encoding (each) in CESU-8.
12095 * See: http://en.wikipedia.org/wiki/Surrogate_pair
12096 *
12097 * 20-bit codepoint, 10 bits (A and B) per surrogate pair:
12098 *
12099 * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
12100 * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff))
12101 * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff))
12102 *
12103 * Encoded into CESU-8:
12104 *
12105 * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f))
12106 * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f))
12107 * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f))
12108 * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f))
12109 * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f))
12110 * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f))
12111 *
12112 * Note that 0x10000 must be subtracted first. The code below
12113 * avoids the sp1, sp2 temporaries which saves around 20 bytes
12114 * of code.
12115 */
12116
12117 x -= 0x10000UL;
12118
12119 out[0] = (duk_uint8_t) (0xed);
12120 out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
12121 out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
12122 out[3] = (duk_uint8_t) (0xed);
12123 out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
12124 out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
12125 len = 6;
12126 }
12127
12128 return len;
12129}
12130
12131/* Decode helper. Return zero on error. */
12132DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) {
12133 const duk_uint8_t *p;
12134 duk_uint32_t res;
12135 duk_uint_fast8_t ch;
12136 duk_small_int_t n;
12137
12138 DUK_UNREF(thr);
12139
12140 p = *ptr;
12141 if (p < ptr_start || p >= ptr_end) {
12142 goto fail;
12143 }
12144
12145 /*
12146 * UTF-8 decoder which accepts longer than standard byte sequences.
12147 * This allows full 32-bit code points to be used.
12148 */
12149
12150 ch = (duk_uint_fast8_t) (*p++);
12151 if (ch < 0x80) {
12152 /* 0xxx xxxx [7 bits] */
12153 res = (duk_uint32_t) (ch & 0x7f);
12154 n = 0;
12155 } else if (ch < 0xc0) {
12156 /* 10xx xxxx -> invalid */
12157 goto fail;
12158 } else if (ch < 0xe0) {
12159 /* 110x xxxx 10xx xxxx [11 bits] */
12160 res = (duk_uint32_t) (ch & 0x1f);
12161 n = 1;
12162 } else if (ch < 0xf0) {
12163 /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */
12164 res = (duk_uint32_t) (ch & 0x0f);
12165 n = 2;
12166 } else if (ch < 0xf8) {
12167 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */
12168 res = (duk_uint32_t) (ch & 0x07);
12169 n = 3;
12170 } else if (ch < 0xfc) {
12171 /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */
12172 res = (duk_uint32_t) (ch & 0x03);
12173 n = 4;
12174 } else if (ch < 0xfe) {
12175 /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */
12176 res = (duk_uint32_t) (ch & 0x01);
12177 n = 5;
12178 } else if (ch < 0xff) {
12179 /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */
12180 res = (duk_uint32_t) (0);
12181 n = 6;
12182 } else {
12183 /* 8-byte format could be:
12184 * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits]
12185 *
12186 * However, this format would not have a zero bit following the
12187 * leading one bits and would not allow 0xFF to be used as an
12188 * "invalid xutf-8" marker for internal keys. Further, 8-byte
12189 * encodings (up to 41 bit code points) are not currently needed.
12190 */
12191 goto fail;
12192 }
12193
12194 DUK_ASSERT(p >= ptr_start); /* verified at beginning */
12195 if (p + n > ptr_end) {
12196 /* check pointer at end */
12197 goto fail;
12198 }
12199
12200 while (n > 0) {
12201 DUK_ASSERT(p >= ptr_start && p < ptr_end);
12202 ch = (duk_uint_fast8_t) (*p++);
12203#if 0
12204 if (ch & 0xc0 != 0x80) {
12205 /* not a continuation byte */
12206 p--;
12207 *ptr = p;
12208 *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
12209 return 1;
12210 }
12211#endif
12212 res = (res << 6) + (duk_uint32_t) (ch & 0x3f);
12213 n--;
12214 }
12215
12216 *ptr = p;
12217 *out_cp = res;
12218 return 1;
12219
12220 fail:
12221 return 0;
12222}
12223
12224/* used by e.g. duk_regexp_executor.c, string built-ins */
12225DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end) {
12226 duk_ucodepoint_t cp;
12227
12228 if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
12229 return cp;
12230 }
12231 DUK_ERROR_INTERNAL(thr);
12232 DUK_WO_NORETURN(return 0;);
12233}
12234
12235/* Compute (extended) utf-8 length without codepoint encoding validation,
12236 * used for string interning.
12237 *
12238 * NOTE: This algorithm is performance critical, more so than string hashing
12239 * in some cases. It is needed when interning a string and needs to scan
12240 * every byte of the string with no skipping. Having an ASCII fast path
12241 * is useful if possible in the algorithm. The current algorithms were
12242 * chosen from several variants, based on x64 gcc -O2 testing. See:
12243 * https://github.com/svaarala/duktape/pull/422
12244 *
12245 * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length().
12246 */
12247
12248#if defined(DUK_USE_PREFER_SIZE)
12249/* Small variant; roughly 150 bytes smaller than the fast variant. */
12250DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
12251 const duk_uint8_t *p;
12252 const duk_uint8_t *p_end;
12253 duk_size_t ncont;
12254 duk_size_t clen;
12255
12256 p = data;
12257 p_end = data + blen;
12258 ncont = 0;
12259 while (p != p_end) {
12260 duk_uint8_t x;
12261 x = *p++;
12262 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12263 ncont++;
12264 }
12265 }
12266
12267 DUK_ASSERT(ncont <= blen);
12268 clen = blen - ncont;
12269 DUK_ASSERT(clen <= blen);
12270 return clen;
12271}
12272#else /* DUK_USE_PREFER_SIZE */
12273/* This seems like a good overall approach. Fast path for ASCII in 4 byte
12274 * blocks.
12275 */
12276DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
12277 const duk_uint8_t *p;
12278 const duk_uint8_t *p_end;
12279 const duk_uint32_t *p32_end;
12280 const duk_uint32_t *p32;
12281 duk_size_t ncont;
12282 duk_size_t clen;
12283
12284 ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
12285 p = data;
12286 p_end = data + blen;
12287 if (blen < 16) {
12288 goto skip_fastpath;
12289 }
12290
12291 /* Align 'p' to 4; the input data may have arbitrary alignment.
12292 * End of string check not needed because blen >= 16.
12293 */
12294 while (((duk_size_t) (const void *) p) & 0x03U) {
12295 duk_uint8_t x;
12296 x = *p++;
12297 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12298 ncont++;
12299 }
12300 }
12301
12302 /* Full, aligned 4-byte reads. */
12303 p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
12304 p32 = (const duk_uint32_t *) (const void *) p;
12305 while (p32 != (const duk_uint32_t *) p32_end) {
12306 duk_uint32_t x;
12307 x = *p32++;
12308 if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
12309 ; /* ASCII fast path */
12310 } else {
12311 /* Flip highest bit of each byte which changes
12312 * the bit pattern 10xxxxxx into 00xxxxxx which
12313 * allows an easy bit mask test.
12314 */
12315 x ^= 0x80808080UL;
12316 if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
12317 ncont++;
12318 }
12319 if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
12320 ncont++;
12321 }
12322 if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
12323 ncont++;
12324 }
12325 if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
12326 ncont++;
12327 }
12328 }
12329 }
12330 p = (const duk_uint8_t *) p32;
12331 /* Fall through to handle the rest. */
12332
12333 skip_fastpath:
12334 while (p != p_end) {
12335 duk_uint8_t x;
12336 x = *p++;
12337 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12338 ncont++;
12339 }
12340 }
12341
12342 DUK_ASSERT(ncont <= blen);
12343 clen = blen - ncont;
12344 DUK_ASSERT(clen <= blen);
12345 return clen;
12346}
12347#endif /* DUK_USE_PREFER_SIZE */
12348
12349/* Check whether a string is UTF-8 compatible or not. */
12350DUK_INTERNAL duk_bool_t duk_unicode_is_utf8_compatible(const duk_uint8_t *buf, duk_size_t len) {
12351 duk_size_t i = 0;
12352#if !defined(DUK_USE_PREFER_SIZE)
12353 duk_size_t len_safe;
12354#endif
12355
12356 /* Many practical strings are ASCII only, so use a fast path check
12357 * to check chunks of bytes at once with minimal branch cost.
12358 */
12359#if !defined(DUK_USE_PREFER_SIZE)
12360 len_safe = len & ~0x03UL;
12361 for (; i < len_safe; i += 4) {
12362 duk_uint8_t t = buf[i] | buf[i + 1] | buf[i + 2] | buf[i + 3];
12363 if (DUK_UNLIKELY((t & 0x80U) != 0U)) {
12364 /* At least one byte was outside 0x00-0x7f, break
12365 * out to slow path (and remain there).
12366 *
12367 * XXX: We could also deal with the problem character
12368 * and resume fast path later.
12369 */
12370 break;
12371 }
12372 }
12373#endif
12374
12375 for (; i < len;) {
12376 duk_uint8_t t;
12377 duk_size_t left;
12378 duk_size_t ncont;
12379 duk_uint32_t cp;
12380 duk_uint32_t mincp;
12381
12382 t = buf[i++];
12383 if (DUK_LIKELY((t & 0x80U) == 0U)) {
12384 /* Fast path, ASCII. */
12385 continue;
12386 }
12387
12388 /* Non-ASCII start byte, slow path.
12389 *
12390 * 10xx xxxx -> continuation byte
12391 * 110x xxxx + 1*CONT -> [0x80, 0x7ff]
12392 * 1110 xxxx + 2*CONT -> [0x800, 0xffff], must reject [0xd800,0xdfff]
12393 * 1111 0xxx + 3*CONT -> [0x10000, 0x10ffff]
12394 */
12395 left = len - i;
12396 if (t <= 0xdfU) { /* 1101 1111 = 0xdf */
12397 if (t <= 0xbfU) { /* 1011 1111 = 0xbf */
12398 return 0;
12399 }
12400 ncont = 1;
12401 mincp = 0x80UL;
12402 cp = t & 0x1fU;
12403 } else if (t <= 0xefU) { /* 1110 1111 = 0xef */
12404 ncont = 2;
12405 mincp = 0x800UL;
12406 cp = t & 0x0fU;
12407 } else if (t <= 0xf7U) { /* 1111 0111 = 0xf7 */
12408 ncont = 3;
12409 mincp = 0x10000UL;
12410 cp = t & 0x07U;
12411 } else {
12412 return 0;
12413 }
12414 if (left < ncont) {
12415 return 0;
12416 }
12417 while (ncont > 0U) {
12418 t = buf[i++];
12419 if ((t & 0xc0U) != 0x80U) { /* 10xx xxxx */
12420 return 0;
12421 }
12422 cp = (cp << 6) + (t & 0x3fU);
12423 ncont--;
12424 }
12425 if (cp < mincp || cp > 0x10ffffUL || (cp >= 0xd800UL && cp <= 0xdfffUL)) {
12426 return 0;
12427 }
12428 }
12429
12430 return 1;
12431}
12432
12433/*
12434 * Unicode range matcher
12435 *
12436 * Matches a codepoint against a packed bitstream of character ranges.
12437 * Used for slow path Unicode matching.
12438 */
12439
12440/* Must match tools/extract_chars.py, generate_match_table3(). */
12441DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
12442 duk_uint32_t t;
12443
12444 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
12445 if (t <= 0x0eU) {
12446 return t;
12447 }
12448 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
12449 if (t <= 0xfdU) {
12450 return t + 0x0f;
12451 }
12452 if (t == 0xfeU) {
12453 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
12454 return t + 0x0fU + 0xfeU;
12455 } else {
12456 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
12457 return t + 0x0fU + 0xfeU + 0x1000UL;
12458 }
12459}
12460
12461DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
12462 duk_bitdecoder_ctx bd_ctx;
12463 duk_codepoint_t prev_re;
12464
12465 duk_memzero(&bd_ctx, sizeof(bd_ctx));
12466 bd_ctx.data = (const duk_uint8_t *) unitab;
12467 bd_ctx.length = (duk_size_t) unilen;
12468
12469 prev_re = 0;
12470 for (;;) {
12471 duk_codepoint_t r1, r2;
12472 r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
12473 if (r1 == 0) {
12474 break;
12475 }
12476 r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
12477
12478 r1 = prev_re + r1;
12479 r2 = r1 + r2;
12480 prev_re = r2;
12481
12482 /* [r1,r2] is the range */
12483
12484 DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
12485 (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
12486 if (cp >= r1 && cp <= r2) {
12487 return 1;
12488 }
12489 }
12490
12491 return 0;
12492}
12493
12494/*
12495 * "WhiteSpace" production check.
12496 */
12497
12498DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
12499 /*
12500 * E5 Section 7.2 specifies six characters specifically as
12501 * white space:
12502 *
12503 * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
12504 * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
12505 * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
12506 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
12507 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
12508 * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
12509 *
12510 * It also specifies any Unicode category 'Zs' characters as white
12511 * space. These can be extracted with the "tools/extract_chars.py" script.
12512 * Current result:
12513 *
12514 * RAW OUTPUT:
12515 * ===========
12516 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
12517 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
12518 * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
12519 * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
12520 * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
12521 * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
12522 * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12523 * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12524 * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12525 * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12526 * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12527 * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
12528 * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12529 * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12530 * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12531 * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
12532 * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12533 * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
12534 *
12535 * RANGES:
12536 * =======
12537 * 0x0020
12538 * 0x00a0
12539 * 0x1680
12540 * 0x180e
12541 * 0x2000 ... 0x200a
12542 * 0x202f
12543 * 0x205f
12544 * 0x3000
12545 *
12546 * A manual decoder (below) is probably most compact for this.
12547 */
12548
12549 duk_uint_fast8_t lo;
12550 duk_uint_fast32_t hi;
12551
12552 /* cp == -1 (EOF) never matches and causes return value 0 */
12553
12554 lo = (duk_uint_fast8_t) (cp & 0xff);
12555 hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */
12556
12557 if (hi == 0x0000UL) {
12558 if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
12559 lo == 0x20U || lo == 0xa0U) {
12560 return 1;
12561 }
12562 } else if (hi == 0x0020UL) {
12563 if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
12564 return 1;
12565 }
12566 } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
12567 cp == 0xfeffL) {
12568 return 1;
12569 }
12570
12571 return 0;
12572}
12573
12574/*
12575 * "LineTerminator" production check.
12576 */
12577
12578DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
12579 /*
12580 * E5 Section 7.3
12581 *
12582 * A LineTerminatorSequence essentially merges <CR> <LF> sequences
12583 * into a single line terminator. This must be handled by the caller.
12584 */
12585
12586 if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
12587 cp == 0x2029L) {
12588 return 1;
12589 }
12590
12591 return 0;
12592}
12593
12594/*
12595 * "IdentifierStart" production check.
12596 */
12597
12598DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
12599 /*
12600 * E5 Section 7.6:
12601 *
12602 * IdentifierStart:
12603 * UnicodeLetter
12604 * $
12605 * _
12606 * \ UnicodeEscapeSequence
12607 *
12608 * IdentifierStart production has one multi-character production:
12609 *
12610 * \ UnicodeEscapeSequence
12611 *
12612 * The '\' character is -not- matched by this function. Rather, the caller
12613 * should decode the escape and then call this function to check whether the
12614 * decoded character is acceptable (see discussion in E5 Section 7.6).
12615 *
12616 * The "UnicodeLetter" alternative of the production allows letters
12617 * from various Unicode categories. These can be extracted with the
12618 * "tools/extract_chars.py" script.
12619 *
12620 * Because the result has hundreds of Unicode codepoint ranges, matching
12621 * for any values >= 0x80 are done using a very slow range-by-range scan
12622 * and a packed range format.
12623 *
12624 * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
12625 * it matters the most. The ASCII related ranges of IdentifierStart are:
12626 *
12627 * 0x0041 ... 0x005a ['A' ... 'Z']
12628 * 0x0061 ... 0x007a ['a' ... 'z']
12629 * 0x0024 ['$']
12630 * 0x005f ['_']
12631 */
12632
12633 /* ASCII (and EOF) fast path -- quick accept and reject */
12634 if (cp <= 0x7fL) {
12635#if defined(DUK_USE_IDCHAR_FASTPATH)
12636 return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
12637#else
12638 if ((cp >= 'a' && cp <= 'z') ||
12639 (cp >= 'A' && cp <= 'Z') ||
12640 cp == '_' || cp == '$') {
12641 return 1;
12642 }
12643 return 0;
12644#endif
12645 }
12646
12647 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12648
12649#if defined(DUK_USE_SOURCE_NONBMP)
12650 if (duk__uni_range_match(duk_unicode_ids_noa,
12651 (duk_size_t) sizeof(duk_unicode_ids_noa),
12652 (duk_codepoint_t) cp)) {
12653 return 1;
12654 }
12655 return 0;
12656#else
12657 if (cp < 0x10000L) {
12658 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12659 sizeof(duk_unicode_ids_noabmp),
12660 (duk_codepoint_t) cp)) {
12661 return 1;
12662 }
12663 return 0;
12664 } else {
12665 /* without explicit non-BMP support, assume non-BMP characters
12666 * are always accepted as identifier characters.
12667 */
12668 return 1;
12669 }
12670#endif
12671}
12672
12673/*
12674 * "IdentifierPart" production check.
12675 */
12676
12677DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
12678 /*
12679 * E5 Section 7.6:
12680 *
12681 * IdentifierPart:
12682 * IdentifierStart
12683 * UnicodeCombiningMark
12684 * UnicodeDigit
12685 * UnicodeConnectorPunctuation
12686 * <ZWNJ> [U+200C]
12687 * <ZWJ> [U+200D]
12688 *
12689 * IdentifierPart production has one multi-character production
12690 * as part of its IdentifierStart alternative. The '\' character
12691 * of an escape sequence is not matched here, see discussion in
12692 * duk_unicode_is_identifier_start().
12693 *
12694 * To match non-ASCII characters (codepoints >= 0x80), a very slow
12695 * linear range-by-range scan is used. The codepoint is first compared
12696 * to the IdentifierStart ranges, and if it doesn't match, then to a
12697 * set consisting of code points in IdentifierPart but not in
12698 * IdentifierStart. This is done to keep the unicode range data small,
12699 * at the expense of speed.
12700 *
12701 * The ASCII fast path consists of:
12702 *
12703 * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit]
12704 * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart]
12705 * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart]
12706 * 0x0024 ['$', IdentifierStart]
12707 * 0x005f ['_', IdentifierStart and
12708 * UnicodeConnectorPunctuation]
12709 *
12710 * UnicodeCombiningMark has no code points <= 0x7f.
12711 *
12712 * The matching code reuses the "identifier start" tables, and then
12713 * consults a separate range set for characters in "identifier part"
12714 * but not in "identifier start". These can be extracted with the
12715 * "tools/extract_chars.py" script.
12716 *
12717 * UnicodeCombiningMark -> categories Mn, Mc
12718 * UnicodeDigit -> categories Nd
12719 * UnicodeConnectorPunctuation -> categories Pc
12720 */
12721
12722 /* ASCII (and EOF) fast path -- quick accept and reject */
12723 if (cp <= 0x7fL) {
12724#if defined(DUK_USE_IDCHAR_FASTPATH)
12725 return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
12726#else
12727 if ((cp >= 'a' && cp <= 'z') ||
12728 (cp >= 'A' && cp <= 'Z') ||
12729 (cp >= '0' && cp <= '9') ||
12730 cp == '_' || cp == '$') {
12731 return 1;
12732 }
12733 return 0;
12734#endif
12735 }
12736
12737 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12738
12739#if defined(DUK_USE_SOURCE_NONBMP)
12740 if (duk__uni_range_match(duk_unicode_ids_noa,
12741 sizeof(duk_unicode_ids_noa),
12742 (duk_codepoint_t) cp) ||
12743 duk__uni_range_match(duk_unicode_idp_m_ids_noa,
12744 sizeof(duk_unicode_idp_m_ids_noa),
12745 (duk_codepoint_t) cp)) {
12746 return 1;
12747 }
12748 return 0;
12749#else
12750 if (cp < 0x10000L) {
12751 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12752 sizeof(duk_unicode_ids_noabmp),
12753 (duk_codepoint_t) cp) ||
12754 duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
12755 sizeof(duk_unicode_idp_m_ids_noabmp),
12756 (duk_codepoint_t) cp)) {
12757 return 1;
12758 }
12759 return 0;
12760 } else {
12761 /* without explicit non-BMP support, assume non-BMP characters
12762 * are always accepted as identifier characters.
12763 */
12764 return 1;
12765 }
12766#endif
12767}
12768
12769/*
12770 * Unicode letter check.
12771 */
12772
12773DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
12774 /*
12775 * Unicode letter is now taken to be the categories:
12776 *
12777 * Lu, Ll, Lt, Lm, Lo
12778 *
12779 * (Not sure if this is exactly correct.)
12780 *
12781 * The ASCII fast path consists of:
12782 *
12783 * 0x0041 ... 0x005a ['A' ... 'Z']
12784 * 0x0061 ... 0x007a ['a' ... 'z']
12785 */
12786
12787 /* ASCII (and EOF) fast path -- quick accept and reject */
12788 if (cp <= 0x7fL) {
12789 if ((cp >= 'a' && cp <= 'z') ||
12790 (cp >= 'A' && cp <= 'Z')) {
12791 return 1;
12792 }
12793 return 0;
12794 }
12795
12796 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12797
12798#if defined(DUK_USE_SOURCE_NONBMP)
12799 if (duk__uni_range_match(duk_unicode_ids_noa,
12800 sizeof(duk_unicode_ids_noa),
12801 (duk_codepoint_t) cp) &&
12802 !duk__uni_range_match(duk_unicode_ids_m_let_noa,
12803 sizeof(duk_unicode_ids_m_let_noa),
12804 (duk_codepoint_t) cp)) {
12805 return 1;
12806 }
12807 return 0;
12808#else
12809 if (cp < 0x10000L) {
12810 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12811 sizeof(duk_unicode_ids_noabmp),
12812 (duk_codepoint_t) cp) &&
12813 !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
12814 sizeof(duk_unicode_ids_m_let_noabmp),
12815 (duk_codepoint_t) cp)) {
12816 return 1;
12817 }
12818 return 0;
12819 } else {
12820 /* without explicit non-BMP support, assume non-BMP characters
12821 * are always accepted as letters.
12822 */
12823 return 1;
12824 }
12825#endif
12826}
12827
12828/*
12829 * Complex case conversion helper which decodes a bit-packed conversion
12830 * control stream generated by tools/extract_caseconv.py. The conversion
12831 * is very slow because it runs through the conversion data in a linear
12832 * fashion to save space (which is why ASCII characters have a special
12833 * fast path before arriving here).
12834 *
12835 * The particular bit counts etc have been determined experimentally to
12836 * be small but still sufficient, and must match the Python script
12837 * (tools/extract_caseconv.py).
12838 *
12839 * The return value is the case converted codepoint or -1 if the conversion
12840 * results in multiple characters (this is useful for regexp Canonicalization
12841 * operation). If 'buf' is not NULL, the result codepoint(s) are also
12842 * appended to the hbuffer.
12843 *
12844 * Context and locale specific rules must be checked before consulting
12845 * this function.
12846 */
12847
12848DUK_LOCAL
12849duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
12850 duk_bufwriter_ctx *bw,
12851 duk_codepoint_t cp,
12852 duk_bitdecoder_ctx *bd_ctx) {
12853 duk_small_int_t skip = 0;
12854 duk_small_int_t n;
12855 duk_small_int_t t;
12856 duk_small_int_t count;
12857 duk_codepoint_t tmp_cp;
12858 duk_codepoint_t start_i;
12859 duk_codepoint_t start_o;
12860
12861 DUK_ASSERT(bd_ctx != NULL);
12862 DUK_UNREF(thr);
12863
12864 DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
12865
12866 /* range conversion with a "skip" */
12867 DUK_DDD(DUK_DDDPRINT("checking ranges"));
12868 for (;;) {
12869 skip++;
12870 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
12871 if (n == 0x3f) {
12872 /* end marker */
12873 break;
12874 }
12875 DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
12876
12877 while (n--) {
12878 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12879 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12880 count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12881 DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
12882 (long) start_i, (long) start_o, (long) count, (long) skip));
12883
12884 if (cp >= start_i) {
12885 tmp_cp = cp - start_i; /* always >= 0 */
12886 if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
12887 (tmp_cp % (duk_codepoint_t) skip) == 0) {
12888 DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
12889 cp = start_o + tmp_cp;
12890 goto single;
12891 }
12892 }
12893 }
12894 }
12895
12896 /* 1:1 conversion */
12897 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12898 DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
12899 while (n--) {
12900 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12901 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12902 DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
12903 if (cp == start_i) {
12904 DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
12905 cp = start_o;
12906 goto single;
12907 }
12908 }
12909
12910 /* complex, multicharacter conversion */
12911 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12912 DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
12913 while (n--) {
12914 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12915 t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
12916 DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
12917 if (cp == start_i) {
12918 DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
12919 if (bw != NULL) {
12920 while (t--) {
12921 tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12922 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
12923 }
12924 }
12925 return -1;
12926 } else {
12927 while (t--) {
12928 (void) duk_bd_decode(bd_ctx, 16);
12929 }
12930 }
12931 }
12932
12933 /* default: no change */
12934 DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
12935 /* fall through */
12936
12937 single:
12938 if (bw != NULL) {
12939 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
12940 }
12941 return cp;
12942}
12943
12944/*
12945 * Case conversion helper, with context/local sensitivity.
12946 * For proper case conversion, one needs to know the character
12947 * and the preceding and following characters, as well as
12948 * locale/language.
12949 */
12950
12951/* XXX: add 'language' argument when locale/language sensitive rule
12952 * support added.
12953 */
12954DUK_LOCAL
12955duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
12956 duk_bufwriter_ctx *bw,
12957 duk_codepoint_t cp,
12958 duk_codepoint_t prev,
12959 duk_codepoint_t next,
12960 duk_bool_t uppercase) {
12961 duk_bitdecoder_ctx bd_ctx;
12962
12963 /* fast path for ASCII */
12964 if (cp < 0x80L) {
12965 /* XXX: there are language sensitive rules for the ASCII range.
12966 * If/when language/locale support is implemented, they need to
12967 * be implemented here for the fast path. There are no context
12968 * sensitive rules for ASCII range.
12969 */
12970
12971 if (uppercase) {
12972 if (cp >= 'a' && cp <= 'z') {
12973 cp = cp - 'a' + 'A';
12974 }
12975 } else {
12976 if (cp >= 'A' && cp <= 'Z') {
12977 cp = cp - 'A' + 'a';
12978 }
12979 }
12980
12981 if (bw != NULL) {
12982 DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
12983 }
12984 return cp;
12985 }
12986
12987 /* context and locale specific rules which cannot currently be represented
12988 * in the caseconv bitstream: hardcoded rules in C
12989 */
12990 if (uppercase) {
12991 /* XXX: turkish / azeri */
12992 } else {
12993 /*
12994 * Final sigma context specific rule. This is a rather tricky
12995 * rule and this handling is probably not 100% correct now.
12996 * The rule is not locale/language specific so it is supported.
12997 */
12998
12999 if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
13000 duk_unicode_is_letter(prev) && /* prev exists and is not a letter */
13001 !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */
13002 /* Capital sigma occurred at "end of word", lowercase to
13003 * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise
13004 * fall through and let the normal rules lowercase it to
13005 * U+03C3 = GREEK SMALL LETTER SIGMA.
13006 */
13007 cp = 0x03c2L;
13008 goto singlechar;
13009 }
13010
13011 /* XXX: lithuanian not implemented */
13012 /* XXX: lithuanian, explicit dot rules */
13013 /* XXX: turkish / azeri, lowercase rules */
13014 }
13015
13016 /* 1:1 or special conversions, but not locale/context specific: script generated rules */
13017 duk_memzero(&bd_ctx, sizeof(bd_ctx));
13018 if (uppercase) {
13019 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
13020 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
13021 } else {
13022 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
13023 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
13024 }
13025 return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
13026
13027 singlechar:
13028 if (bw != NULL) {
13029 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
13030 }
13031 return cp;
13032
13033 /* unused now, not needed until Turkish/Azeri */
13034#if 0
13035 nochar:
13036 return -1;
13037#endif
13038}
13039
13040/*
13041 * Replace valstack top with case converted version.
13042 */
13043
13044DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) {
13045 duk_hstring *h_input;
13046 duk_bufwriter_ctx bw_alloc;
13047 duk_bufwriter_ctx *bw;
13048 const duk_uint8_t *p, *p_start, *p_end;
13049 duk_codepoint_t prev, curr, next;
13050
13051 h_input = duk_require_hstring(thr, -1); /* Accept symbols. */
13052 DUK_ASSERT(h_input != NULL);
13053
13054 bw = &bw_alloc;
13055 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
13056
13057 /* [ ... input buffer ] */
13058
13059 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
13060 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
13061 p = p_start;
13062
13063 prev = -1; DUK_UNREF(prev);
13064 curr = -1;
13065 next = -1;
13066 for (;;) {
13067 prev = curr;
13068 curr = next;
13069 next = -1;
13070 if (p < p_end) {
13071 next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
13072 } else {
13073 /* end of input and last char has been processed */
13074 if (curr < 0) {
13075 break;
13076 }
13077 }
13078
13079 /* on first round, skip */
13080 if (curr >= 0) {
13081 /* XXX: could add a fast path to process chunks of input codepoints,
13082 * but relative benefit would be quite small.
13083 */
13084
13085 /* Ensure space for maximum multi-character result; estimate is overkill. */
13086 DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
13087
13088 duk__case_transform_helper(thr,
13089 bw,
13090 (duk_codepoint_t) curr,
13091 prev,
13092 next,
13093 uppercase);
13094 }
13095 }
13096
13097 DUK_BW_COMPACT(thr, bw);
13098 (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */
13099 /* invalidates h_buf pointer */
13100 duk_remove_m2(thr);
13101}
13102
13103#if defined(DUK_USE_REGEXP_SUPPORT)
13104
13105/*
13106 * Canonicalize() abstract operation needed for canonicalization of individual
13107 * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
13108 * Note that codepoints are canonicalized one character at a time, so no context
13109 * specific rules can apply. Locale specific rules can apply, though.
13110 */
13111
13112DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
13113#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
13114 /* Fast canonicalization lookup at the cost of 128kB footprint. */
13115 DUK_ASSERT(cp >= 0);
13116 DUK_UNREF(thr);
13117 if (DUK_LIKELY(cp < 0x10000L)) {
13118 return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
13119 }
13120 return cp;
13121#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
13122 duk_codepoint_t y;
13123
13124 y = duk__case_transform_helper(thr,
13125 NULL, /* NULL is allowed, no output */
13126 cp, /* curr char */
13127 -1, /* prev char */
13128 -1, /* next char */
13129 1); /* uppercase */
13130
13131 if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
13132 /* multiple codepoint conversion or non-ASCII mapped to ASCII
13133 * --> leave as is.
13134 */
13135 return cp;
13136 }
13137
13138 return y;
13139#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
13140}
13141
13142/*
13143 * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume
13144 * x < 0 for characters read outside the string.
13145 */
13146
13147DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
13148 /*
13149 * Note: the description in E5 Section 15.10.2.6 has a typo, it
13150 * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
13151 */
13152 if ((x >= '0' && x <= '9') ||
13153 (x >= 'a' && x <= 'z') ||
13154 (x >= 'A' && x <= 'Z') ||
13155 (x == '_')) {
13156 return 1;
13157 }
13158 return 0;
13159}
13160
13161/*
13162 * Regexp range tables
13163 */
13164
13165/* exposed because lexer needs these too */
13166DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
13167 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
13168};
13169DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
13170 (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
13171 (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
13172 (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
13173 (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
13174 (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
13175 (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
13176 (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
13177 (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
13178 (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
13179 (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
13180 (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
13181};
13182DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
13183 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
13184 (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
13185 (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
13186 (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
13187};
13188DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
13189 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
13190 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
13191};
13192DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
13193 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
13194 (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
13195 (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
13196 (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
13197 (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
13198 (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
13199 (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
13200 (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
13201 (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
13202 (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
13203 (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
13204 (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
13205};
13206DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
13207 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
13208 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
13209 (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
13210 (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
13211 (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
13212};
13213
13214#endif /* DUK_USE_REGEXP_SUPPORT */
13215#line 1 "duk_util_memrw.c"
13216/*
13217 * Macro support functions for reading/writing raw data.
13218 *
13219 * These are done using memcpy to ensure they're valid even for unaligned
13220 * reads/writes on platforms where alignment counts. On x86 at least gcc
13221 * is able to compile these into a bswap+mov. "Always inline" is used to
13222 * ensure these macros compile to minimal code.
13223 */
13224
13225/* #include duk_internal.h -> already included */
13226
13227union duk__u16_union {
13228 duk_uint8_t b[2];
13229 duk_uint16_t x;
13230};
13231typedef union duk__u16_union duk__u16_union;
13232
13233union duk__u32_union {
13234 duk_uint8_t b[4];
13235 duk_uint32_t x;
13236};
13237typedef union duk__u32_union duk__u32_union;
13238
13239#if defined(DUK_USE_64BIT_OPS)
13240union duk__u64_union {
13241 duk_uint8_t b[8];
13242 duk_uint64_t x;
13243};
13244typedef union duk__u64_union duk__u64_union;
13245#endif
13246
13247DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(const duk_uint8_t *p) {
13248 duk__u16_union u;
13249 duk_memcpy((void *) u.b, (const void *) p, (size_t) 2);
13250 u.x = DUK_NTOH16(u.x);
13251 return u.x;
13252}
13253
13254DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(const duk_uint8_t *p) {
13255 duk__u32_union u;
13256 duk_memcpy((void *) u.b, (const void *) p, (size_t) 4);
13257 u.x = DUK_NTOH32(u.x);
13258 return u.x;
13259}
13260
13261DUK_INTERNAL DUK_ALWAYS_INLINE duk_float_t duk_raw_read_float_be(const duk_uint8_t *p) {
13262 duk_float_union fu;
13263 duk_memcpy((void *) fu.uc, (const void *) p, (size_t) 4);
13264 duk_fltunion_big_to_host(&fu);
13265 return fu.f;
13266}
13267
13268DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(const duk_uint8_t *p) {
13269 duk_double_union du;
13270 duk_memcpy((void *) du.uc, (const void *) p, (size_t) 8);
13271 duk_dblunion_big_to_host(&du);
13272 return du.d;
13273}
13274
13275DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_readinc_u16_be(const duk_uint8_t **p) {
13276 duk_uint16_t res = duk_raw_read_u16_be(*p);
13277 *p += 2;
13278 return res;
13279}
13280
13281DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_readinc_u32_be(const duk_uint8_t **p) {
13282 duk_uint32_t res = duk_raw_read_u32_be(*p);
13283 *p += 4;
13284 return res;
13285}
13286
13287DUK_INTERNAL DUK_ALWAYS_INLINE duk_float_t duk_raw_readinc_float_be(const duk_uint8_t **p) {
13288 duk_float_t res = duk_raw_read_float_be(*p);
13289 *p += 4;
13290 return res;
13291}
13292
13293DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_readinc_double_be(const duk_uint8_t **p) {
13294 duk_double_t res = duk_raw_read_double_be(*p);
13295 *p += 8;
13296 return res;
13297}
13298
13299DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t *p, duk_uint16_t val) {
13300 duk__u16_union u;
13301 u.x = DUK_HTON16(val);
13302 duk_memcpy((void *) p, (const void *) u.b, (size_t) 2);
13303}
13304
13305DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t *p, duk_uint32_t val) {
13306 duk__u32_union u;
13307 u.x = DUK_HTON32(val);
13308 duk_memcpy((void *) p, (const void *) u.b, (size_t) 4);
13309}
13310
13311DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_float_be(duk_uint8_t *p, duk_float_t val) {
13312 duk_float_union fu;
13313 fu.f = val;
13314 duk_fltunion_host_to_big(&fu);
13315 duk_memcpy((void *) p, (const void *) fu.uc, (size_t) 4);
13316}
13317
13318DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t *p, duk_double_t val) {
13319 duk_double_union du;
13320 du.d = val;
13321 duk_dblunion_host_to_big(&du);
13322 duk_memcpy((void *) p, (const void *) du.uc, (size_t) 8);
13323}
13324
13325DUK_INTERNAL duk_small_int_t duk_raw_write_xutf8(duk_uint8_t *p, duk_ucodepoint_t val) {
13326 duk_small_int_t len = duk_unicode_encode_xutf8(val, p);
13327 return len;
13328}
13329
13330DUK_INTERNAL duk_small_int_t duk_raw_write_cesu8(duk_uint8_t *p, duk_ucodepoint_t val) {
13331 duk_small_int_t len = duk_unicode_encode_cesu8(val, p);
13332 return len;
13333}
13334
13335DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_u16_be(duk_uint8_t **p, duk_uint16_t val) {
13336 duk_raw_write_u16_be(*p, val);
13337 *p += 2;
13338}
13339
13340DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_u32_be(duk_uint8_t **p, duk_uint32_t val) {
13341 duk_raw_write_u32_be(*p, val);
13342 *p += 4;
13343}
13344
13345DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_float_be(duk_uint8_t **p, duk_float_t val) {
13346 duk_raw_write_float_be(*p, val);
13347 *p += 4;
13348}
13349
13350DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_double_be(duk_uint8_t **p, duk_double_t val) {
13351 duk_raw_write_double_be(*p, val);
13352 *p += 8;
13353}
13354
13355DUK_INTERNAL void duk_raw_writeinc_xutf8(duk_uint8_t **p, duk_ucodepoint_t val) {
13356 duk_small_int_t len = duk_unicode_encode_xutf8(val, *p);
13357 *p += len;
13358}
13359
13360DUK_INTERNAL void duk_raw_writeinc_cesu8(duk_uint8_t **p, duk_ucodepoint_t val) {
13361 duk_small_int_t len = duk_unicode_encode_cesu8(val, *p);
13362 *p += len;
13363}
13364#line 1 "duk_util_misc.c"
13365/*
13366 * Misc util stuff.
13367 */
13368
13369/* #include duk_internal.h -> already included */
13370
13371/*
13372 * Lowercase digits for radix values 2 to 36. Also doubles as lowercase
13373 * hex nybble table.
13374 */
13375
13376DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
13377 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
13378 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
13379 DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
13380 DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
13381 DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
13382 DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
13383 DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
13384 DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
13385 DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
13386};
13387
13388DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
13389 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
13390 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
13391 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
13392 DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
13393};
13394
13395/*
13396 * Table for hex decoding ASCII hex digits
13397 */
13398
13399DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
13400 /* -1 if invalid */
13401 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
13402 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
13403 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
13404 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
13405 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
13406 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
13407 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
13408 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
13409 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
13410 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
13411 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
13412 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
13413 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
13414 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
13415 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
13416 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
13417};
13418
13419#if defined(DUK_USE_HEX_FASTPATH)
13420/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
13421DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
13422 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
13423 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
13424 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
13425 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
13426 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
13427 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
13428 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
13429 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
13430 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
13431 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
13432 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
13433 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
13434 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
13435 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
13436 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
13437 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
13438};
13439#endif
13440
13441/*
13442 * Table for hex encoding bytes
13443 */
13444
13445#if defined(DUK_USE_HEX_FASTPATH)
13446/* Lookup to encode one byte directly into 2 characters:
13447 *
13448 * def genhextab(bswap):
13449 * for i in xrange(256):
13450 * t = chr(i).encode('hex')
13451 * if bswap:
13452 * t = t[1] + t[0]
13453 * print('0x' + t.encode('hex') + 'U')
13454 * print('big endian'); genhextab(False)
13455 * print('little endian'); genhextab(True)
13456*/
13457DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
13458#if defined(DUK_USE_INTEGER_BE)
13459 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
13460 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
13461 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
13462 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
13463 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
13464 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
13465 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
13466 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
13467 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
13468 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
13469 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
13470 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
13471 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
13472 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
13473 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
13474 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
13475 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
13476 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
13477 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
13478 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
13479 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
13480 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
13481 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
13482 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
13483 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
13484 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
13485 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
13486 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
13487 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
13488 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
13489 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
13490 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
13491#else /* DUK_USE_INTEGER_BE */
13492 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
13493 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
13494 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
13495 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
13496 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
13497 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
13498 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
13499 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
13500 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
13501 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
13502 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
13503 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
13504 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
13505 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
13506 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
13507 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
13508 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
13509 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
13510 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
13511 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
13512 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
13513 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
13514 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
13515 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
13516 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
13517 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
13518 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
13519 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
13520 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
13521 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
13522 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
13523 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
13524#endif /* DUK_USE_INTEGER_BE */
13525};
13526#endif /* DUK_USE_HEX_FASTPATH */
13527
13528/*
13529 * Arbitrary byteswap for potentially unaligned values
13530 *
13531 * Used to byteswap pointers e.g. in debugger code.
13532 */
13533
13534#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
13535DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
13536 duk_uint8_t tmp;
13537 duk_uint8_t *q = p + len - 1;
13538
13539 while (p - q < 0) {
13540 tmp = *p;
13541 *p = *q;
13542 *q = tmp;
13543 p++;
13544 q--;
13545 }
13546}
13547#endif
13548#line 1 "duk_hobject_class.c"
13549/*
13550 * Hobject ECMAScript [[Class]].
13551 */
13552
13553/* #include duk_internal.h -> already included */
13554
13555#if (DUK_STRIDX_UC_ARGUMENTS > 255)
13556#error constant too large
13557#endif
13558#if (DUK_STRIDX_UC_ARRAY > 255)
13559#error constant too large
13560#endif
13561#if (DUK_STRIDX_UC_BOOLEAN > 255)
13562#error constant too large
13563#endif
13564#if (DUK_STRIDX_UC_DATE > 255)
13565#error constant too large
13566#endif
13567#if (DUK_STRIDX_UC_ERROR > 255)
13568#error constant too large
13569#endif
13570#if (DUK_STRIDX_UC_FUNCTION > 255)
13571#error constant too large
13572#endif
13573#if (DUK_STRIDX_JSON > 255)
13574#error constant too large
13575#endif
13576#if (DUK_STRIDX_MATH > 255)
13577#error constant too large
13578#endif
13579#if (DUK_STRIDX_UC_NUMBER > 255)
13580#error constant too large
13581#endif
13582#if (DUK_STRIDX_UC_OBJECT > 255)
13583#error constant too large
13584#endif
13585#if (DUK_STRIDX_REG_EXP > 255)
13586#error constant too large
13587#endif
13588#if (DUK_STRIDX_UC_STRING > 255)
13589#error constant too large
13590#endif
13591#if (DUK_STRIDX_GLOBAL > 255)
13592#error constant too large
13593#endif
13594#if (DUK_STRIDX_OBJ_ENV > 255)
13595#error constant too large
13596#endif
13597#if (DUK_STRIDX_DEC_ENV > 255)
13598#error constant too large
13599#endif
13600#if (DUK_STRIDX_UC_POINTER > 255)
13601#error constant too large
13602#endif
13603#if (DUK_STRIDX_UC_THREAD > 255)
13604#error constant too large
13605#endif
13606#if (DUK_STRIDX_ARRAY_BUFFER > 255)
13607#error constant too large
13608#endif
13609#if (DUK_STRIDX_DATA_VIEW > 255)
13610#error constant too large
13611#endif
13612#if (DUK_STRIDX_INT8_ARRAY > 255)
13613#error constant too large
13614#endif
13615#if (DUK_STRIDX_UINT8_ARRAY > 255)
13616#error constant too large
13617#endif
13618#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
13619#error constant too large
13620#endif
13621#if (DUK_STRIDX_INT16_ARRAY > 255)
13622#error constant too large
13623#endif
13624#if (DUK_STRIDX_UINT16_ARRAY > 255)
13625#error constant too large
13626#endif
13627#if (DUK_STRIDX_INT32_ARRAY > 255)
13628#error constant too large
13629#endif
13630#if (DUK_STRIDX_UINT32_ARRAY > 255)
13631#error constant too large
13632#endif
13633#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
13634#error constant too large
13635#endif
13636#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
13637#error constant too large
13638#endif
13639#if (DUK_STRIDX_EMPTY_STRING > 255)
13640#error constant too large
13641#endif
13642
13643/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
13644DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
13645 DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */
13646 DUK_STRIDX_UC_OBJECT,
13647 DUK_STRIDX_UC_ARRAY,
13648 DUK_STRIDX_UC_FUNCTION,
13649 DUK_STRIDX_UC_ARGUMENTS,
13650 DUK_STRIDX_UC_BOOLEAN,
13651 DUK_STRIDX_UC_DATE,
13652 DUK_STRIDX_UC_ERROR,
13653 DUK_STRIDX_JSON,
13654 DUK_STRIDX_MATH,
13655 DUK_STRIDX_UC_NUMBER,
13656 DUK_STRIDX_REG_EXP,
13657 DUK_STRIDX_UC_STRING,
13658 DUK_STRIDX_GLOBAL,
13659 DUK_STRIDX_UC_SYMBOL,
13660 DUK_STRIDX_OBJ_ENV,
13661 DUK_STRIDX_DEC_ENV,
13662 DUK_STRIDX_UC_POINTER,
13663 DUK_STRIDX_UC_THREAD,
13664 DUK_STRIDX_ARRAY_BUFFER,
13665 DUK_STRIDX_DATA_VIEW,
13666 DUK_STRIDX_INT8_ARRAY,
13667 DUK_STRIDX_UINT8_ARRAY,
13668 DUK_STRIDX_UINT8_CLAMPED_ARRAY,
13669 DUK_STRIDX_INT16_ARRAY,
13670 DUK_STRIDX_UINT16_ARRAY,
13671 DUK_STRIDX_INT32_ARRAY,
13672 DUK_STRIDX_UINT32_ARRAY,
13673 DUK_STRIDX_FLOAT32_ARRAY,
13674 DUK_STRIDX_FLOAT64_ARRAY,
13675 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
13676 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
13677};
13678#line 1 "duk_alloc_default.c"
13679/*
13680 * Default allocation functions.
13681 *
13682 * Assumes behavior such as malloc allowing zero size, yielding
13683 * a NULL or a unique pointer which is a no-op for free.
13684 */
13685
13686/* #include duk_internal.h -> already included */
13687
13688#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
13689DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
13690 void *res;
13691 DUK_UNREF(udata);
13692 res = DUK_ANSI_MALLOC(size);
13693 DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
13694 (unsigned long) size, (void *) res));
13695 return res;
13696}
13697
13698DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
13699 void *res;
13700 DUK_UNREF(udata);
13701 res = DUK_ANSI_REALLOC(ptr, newsize);
13702 DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
13703 (void *) ptr, (unsigned long) newsize, (void *) res));
13704 return res;
13705}
13706
13707DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
13708 DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
13709 DUK_UNREF(udata);
13710 DUK_ANSI_FREE(ptr);
13711}
13712#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
13713#line 1 "duk_api_buffer.c"
13714/*
13715 * Buffer
13716 */
13717
13718/* #include duk_internal.h -> already included */
13719
13720DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
13721 duk_hbuffer_dynamic *h;
13722
13723 DUK_ASSERT_API_ENTRY(thr);
13724
13725 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
13726 DUK_ASSERT(h != NULL);
13727
13728 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
13729 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13730 DUK_WO_NORETURN(return NULL;);
13731 }
13732
13733 /* Maximum size check is handled by callee. */
13734 duk_hbuffer_resize(thr, h, new_size);
13735
13736 return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
13737}
13738
13739DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
13740 duk_hbuffer_dynamic *h;
13741 void *ptr;
13742 duk_size_t sz;
13743
13744 DUK_ASSERT_API_ENTRY(thr);
13745
13746 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
13747 DUK_ASSERT(h != NULL);
13748
13749 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
13750 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13751 DUK_WO_NORETURN(return NULL;);
13752 }
13753
13754 /* Forget the previous allocation, setting size to 0 and alloc to
13755 * NULL. Caller is responsible for freeing the previous allocation.
13756 * Getting the allocation and clearing it is done in the same API
13757 * call to avoid any chance of a realloc.
13758 */
13759 ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
13760 sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
13761 if (out_size) {
13762 *out_size = sz;
13763 }
13764 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
13765 DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
13766
13767 return ptr;
13768}
13769
13770DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
13771 duk_hbuffer_external *h;
13772
13773 DUK_ASSERT_API_ENTRY(thr);
13774
13775 h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
13776 DUK_ASSERT(h != NULL);
13777
13778 if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
13779 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13780 DUK_WO_NORETURN(return;);
13781 }
13782 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
13783
13784 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
13785 DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
13786}
13787#line 1 "duk_api_bytecode.c"
13788/*
13789 * Bytecode dump/load
13790 *
13791 * The bytecode load primitive is more important performance-wise than the
13792 * dump primitive.
13793 *
13794 * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
13795 * memory safe for invalid arguments - caller beware! There's little point
13796 * in trying to achieve memory safety unless bytecode instructions are also
13797 * validated which is not easy to do with indirect register references etc.
13798 */
13799
13800/* #include duk_internal.h -> already included */
13801
13802#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
13803
13804#define DUK__SER_MARKER 0xbf
13805#define DUK__SER_STRING 0x00
13806#define DUK__SER_NUMBER 0x01
13807#define DUK__BYTECODE_INITIAL_ALLOC 256
13808#define DUK__NO_FORMALS 0xffffffffUL
13809
13810/*
13811 * Dump/load helpers, xxx_raw() helpers do no buffer checks
13812 */
13813
13814DUK_LOCAL const duk_uint8_t *duk__load_string_raw(duk_hthread *thr, const duk_uint8_t *p) {
13815 duk_uint32_t len;
13816
13817 len = DUK_RAW_READINC_U32_BE(p);
13818 duk_push_lstring(thr, (const char *) p, len);
13819 p += len;
13820 return p;
13821}
13822
13823DUK_LOCAL const duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, const duk_uint8_t *p) {
13824 duk_uint32_t len;
13825 duk_uint8_t *buf;
13826
13827 len = DUK_RAW_READINC_U32_BE(p);
13828 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
13829 DUK_ASSERT(buf != NULL);
13830 duk_memcpy((void *) buf, (const void *) p, (size_t) len);
13831 p += len;
13832 return p;
13833}
13834
13835DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
13836 duk_size_t len;
13837 duk_uint32_t tmp32;
13838
13839 DUK_ASSERT(h != NULL);
13840
13841 len = DUK_HSTRING_GET_BYTELEN(h);
13842 DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
13843 tmp32 = (duk_uint32_t) len;
13844 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
13845 duk_memcpy((void *) p,
13846 (const void *) DUK_HSTRING_GET_DATA(h),
13847 len);
13848 p += len;
13849 return p;
13850}
13851
13852DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
13853 duk_size_t len;
13854 duk_uint32_t tmp32;
13855
13856 DUK_ASSERT(thr != NULL);
13857 DUK_ASSERT(h != NULL);
13858 DUK_UNREF(thr);
13859
13860 len = DUK_HBUFFER_GET_SIZE(h);
13861 DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
13862 tmp32 = (duk_uint32_t) len;
13863 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
13864 /* When len == 0, buffer data pointer may be NULL. */
13865 duk_memcpy_unsafe((void *) p,
13866 (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
13867 len);
13868 p += len;
13869 return p;
13870}
13871
13872DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) {
13873 duk_hstring *h_str;
13874 duk_tval *tv;
13875
13876 tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
13877 if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
13878 h_str = DUK_TVAL_GET_STRING(tv);
13879 DUK_ASSERT(h_str != NULL);
13880 } else {
13881 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
13882 DUK_ASSERT(h_str != NULL);
13883 }
13884 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
13885 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
13886 p = duk__dump_hstring_raw(p, h_str);
13887 return p;
13888}
13889
13890DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) {
13891 duk_tval *tv;
13892
13893 tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
13894 if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
13895 duk_hbuffer *h_buf;
13896 h_buf = DUK_TVAL_GET_BUFFER(tv);
13897 DUK_ASSERT(h_buf != NULL);
13898 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
13899 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
13900 p = duk__dump_hbuffer_raw(thr, p, h_buf);
13901 } else {
13902 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13903 DUK_RAW_WRITEINC_U32_BE(p, 0);
13904 }
13905 return p;
13906}
13907
13908DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) {
13909 duk_tval *tv;
13910 duk_uint32_t val;
13911
13912 tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
13913 if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
13914 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
13915 } else {
13916 val = def_value;
13917 }
13918 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13919 DUK_RAW_WRITEINC_U32_BE(p, val);
13920 return p;
13921}
13922
13923DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
13924 duk_hobject *h;
13925
13926 h = duk_hobject_get_varmap(thr, (duk_hobject *) func);
13927 if (h != NULL) {
13928 duk_uint_fast32_t i;
13929
13930 /* We know _Varmap only has own properties so walk property
13931 * table directly. We also know _Varmap is dense and all
13932 * values are numbers; assert for these. GC and finalizers
13933 * shouldn't affect _Varmap so side effects should be fine.
13934 */
13935 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
13936 duk_hstring *key;
13937 duk_tval *tv_val;
13938 duk_uint32_t val;
13939
13940 key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
13941 DUK_ASSERT(key != NULL); /* _Varmap is dense */
13942 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
13943 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
13944 DUK_ASSERT(tv_val != NULL);
13945 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
13946#if defined(DUK_USE_FASTINT)
13947 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
13948 DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
13949 val = DUK_TVAL_GET_FASTINT_U32(tv_val);
13950#else
13951 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
13952#endif
13953
13954 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
13955 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
13956 p = duk__dump_hstring_raw(p, key);
13957 DUK_RAW_WRITEINC_U32_BE(p, val);
13958 }
13959 }
13960 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13961 DUK_RAW_WRITEINC_U32_BE(p, 0); /* end of _Varmap */
13962 return p;
13963}
13964
13965DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
13966 duk_harray *h;
13967
13968 h = duk_hobject_get_formals(thr, (duk_hobject *) func);
13969 if (h != NULL) {
13970 duk_uint32_t i;
13971
13972 /* Here we rely on _Formals being a dense array containing
13973 * strings. This should be the case unless _Formals has been
13974 * tweaked by the application (which we don't support right
13975 * now).
13976 */
13977
13978 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13979 DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
13980 DUK_RAW_WRITEINC_U32_BE(p, h->length);
13981
13982 for (i = 0; i < h->length; i++) {
13983 duk_tval *tv_val;
13984 duk_hstring *varname;
13985
13986 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
13987 DUK_ASSERT(tv_val != NULL);
13988 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
13989
13990 varname = DUK_TVAL_GET_STRING(tv_val);
13991 DUK_ASSERT(varname != NULL);
13992 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
13993
13994 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
13995 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
13996 p = duk__dump_hstring_raw(p, varname);
13997 }
13998 } else {
13999 DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
14000 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
14001 DUK_RAW_WRITEINC_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
14002 }
14003 return p;
14004}
14005
14006static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
14007 duk_tval *tv, *tv_end;
14008 duk_instr_t *ins, *ins_end;
14009 duk_hobject **fn, **fn_end;
14010 duk_hstring *h_str;
14011 duk_uint32_t count_instr;
14012 duk_uint32_t tmp32;
14013 duk_uint16_t tmp16;
14014 duk_double_t d;
14015
14016 DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
14017 "consts=[%p,%p[ (%ld bytes, %ld items), "
14018 "funcs=[%p,%p[ (%ld bytes, %ld items), "
14019 "code=[%p,%p[ (%ld bytes, %ld items)",
14020 (void *) func,
14021 (void *) p,
14022 (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
14023 (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
14024 (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
14025 (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
14026 (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
14027 (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
14028 (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
14029 (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
14030 (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
14031 (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
14032 (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
14033 (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
14034
14035 DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
14036 count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
14037 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
14038
14039 /* Fixed header info. */
14040 tmp32 = count_instr;
14041 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14042 tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
14043 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14044 tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
14045 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14046 tmp16 = func->nregs;
14047 DUK_RAW_WRITEINC_U16_BE(p, tmp16);
14048 tmp16 = func->nargs;
14049 DUK_RAW_WRITEINC_U16_BE(p, tmp16);
14050#if defined(DUK_USE_DEBUGGER_SUPPORT)
14051 tmp32 = func->start_line;
14052 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14053 tmp32 = func->end_line;
14054 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14055#else
14056 DUK_RAW_WRITEINC_U32_BE(p, 0);
14057 DUK_RAW_WRITEINC_U32_BE(p, 0);
14058#endif
14059 tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */
14060 tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */
14061 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14062
14063 /* Bytecode instructions: endian conversion needed unless
14064 * platform is big endian.
14065 */
14066 ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
14067 ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
14068 DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
14069#if defined(DUK_USE_INTEGER_BE)
14070 duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins));
14071 p += (size_t) (ins_end - ins);
14072#else
14073 while (ins != ins_end) {
14074 tmp32 = (duk_uint32_t) (*ins);
14075 DUK_RAW_WRITEINC_U32_BE(p, tmp32);
14076 ins++;
14077 }
14078#endif
14079
14080 /* Constants: variable size encoding. */
14081 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
14082 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
14083 while (tv != tv_end) {
14084 /* constants are strings or numbers now */
14085 DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
14086 DUK_TVAL_IS_NUMBER(tv));
14087
14088 if (DUK_TVAL_IS_STRING(tv)) {
14089 h_str = DUK_TVAL_GET_STRING(tv);
14090 DUK_ASSERT(h_str != NULL);
14091 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
14092 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
14093 *p++ = DUK__SER_STRING;
14094 p = duk__dump_hstring_raw(p, h_str);
14095 } else {
14096 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
14097 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
14098 *p++ = DUK__SER_NUMBER;
14099 d = DUK_TVAL_GET_NUMBER(tv);
14100 DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
14101 }
14102 tv++;
14103 }
14104
14105 /* Inner functions recursively. */
14106 fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
14107 fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
14108 while (fn != fn_end) {
14109 /* XXX: This causes recursion up to inner function depth
14110 * which is normally not an issue, e.g. mark-and-sweep uses
14111 * a recursion limiter to avoid C stack issues. Avoiding
14112 * this would mean some sort of a work list or just refusing
14113 * to serialize deep functions.
14114 */
14115 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
14116 p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
14117 fn++;
14118 }
14119
14120 /* Lexenv and varenv are not dumped. */
14121
14122 /* Object extra properties.
14123 *
14124 * There are some difference between function templates and functions.
14125 * For example, function templates don't have .length and nargs is
14126 * normally used to instantiate the functions.
14127 */
14128
14129 p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
14130#if defined(DUK_USE_FUNC_NAME_PROPERTY)
14131 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
14132#endif
14133#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
14134 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
14135#endif
14136#if defined(DUK_USE_PC2LINE)
14137 p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
14138#endif
14139 p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
14140 p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
14141
14142 DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
14143
14144 return p;
14145}
14146
14147/* Load a function from bytecode. The function object returned here must
14148 * match what is created by duk_js_push_closure() with respect to its flags,
14149 * properties, etc.
14150 *
14151 * NOTE: there are intentionally no input buffer length / bound checks.
14152 * Adding them would be easy but wouldn't ensure memory safety as untrusted
14153 * or broken bytecode is unsafe during execution unless the opcodes themselves
14154 * are validated (which is quite complex, especially for indirect opcodes).
14155 */
14156
14157#define DUK__ASSERT_LEFT(n) do { \
14158 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
14159 } while (0)
14160
14161static const duk_uint8_t *duk__load_func(duk_hthread *thr, const duk_uint8_t *p, const duk_uint8_t *p_end) {
14162 duk_hcompfunc *h_fun;
14163 duk_hbuffer *h_data;
14164 duk_size_t data_size;
14165 duk_uint32_t count_instr, count_const, count_funcs;
14166 duk_uint32_t n;
14167 duk_uint32_t tmp32;
14168 duk_small_uint_t const_type;
14169 duk_uint8_t *fun_data;
14170 duk_uint8_t *q;
14171 duk_idx_t idx_base;
14172 duk_tval *tv1;
14173 duk_uarridx_t arr_idx;
14174 duk_uarridx_t arr_limit;
14175 duk_hobject *func_env;
14176 duk_bool_t need_pop;
14177
14178 /* XXX: There's some overlap with duk_js_closure() here, but
14179 * seems difficult to share code. Ensure that the final function
14180 * looks the same as created by duk_js_closure().
14181 */
14182
14183 DUK_ASSERT(thr != NULL);
14184
14185 DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (const void *) p, (const void *) p_end));
14186
14187 DUK__ASSERT_LEFT(3 * 4);
14188 count_instr = DUK_RAW_READINC_U32_BE(p);
14189 count_const = DUK_RAW_READINC_U32_BE(p);
14190 count_funcs = DUK_RAW_READINC_U32_BE(p);
14191
14192 data_size = sizeof(duk_tval) * count_const +
14193 sizeof(duk_hobject *) * count_funcs +
14194 sizeof(duk_instr_t) * count_instr;
14195
14196 DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
14197 (long) count_instr, (long) count_const,
14198 (long) count_const, (long) data_size));
14199
14200 /* Value stack is used to ensure reachability of constants and
14201 * inner functions being loaded. Require enough space to handle
14202 * large functions correctly.
14203 */
14204 duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
14205 idx_base = duk_get_top(thr);
14206
14207 /* Push function object, init flags etc. This must match
14208 * duk_js_push_closure() quite carefully.
14209 */
14210 h_fun = duk_push_hcompfunc(thr);
14211 DUK_ASSERT(h_fun != NULL);
14212 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
14213 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
14214 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
14215 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
14216 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
14217
14218 h_fun->nregs = DUK_RAW_READINC_U16_BE(p);
14219 h_fun->nargs = DUK_RAW_READINC_U16_BE(p);
14220#if defined(DUK_USE_DEBUGGER_SUPPORT)
14221 h_fun->start_line = DUK_RAW_READINC_U32_BE(p);
14222 h_fun->end_line = DUK_RAW_READINC_U32_BE(p);
14223#else
14224 p += 8; /* skip line info */
14225#endif
14226
14227 /* duk_hcompfunc flags; quite version specific */
14228 tmp32 = DUK_RAW_READINC_U32_BE(p);
14229 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
14230
14231 /* standard prototype (no need to set here, already set) */
14232 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
14233#if 0
14234 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
14235#endif
14236
14237 /* assert just a few critical flags */
14238 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
14239 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
14240 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
14241 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
14242 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj));
14243 DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(&h_fun->obj));
14244 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
14245 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
14246 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
14247
14248 /* Create function 'data' buffer but don't attach it yet. */
14249 fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
14250 DUK_ASSERT(fun_data != NULL);
14251
14252 /* Load bytecode instructions. */
14253 DUK_ASSERT(sizeof(duk_instr_t) == 4);
14254 DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
14255#if defined(DUK_USE_INTEGER_BE)
14256 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
14257 duk_memcpy((void *) q,
14258 (const void *) p,
14259 sizeof(duk_instr_t) * count_instr);
14260 p += sizeof(duk_instr_t) * count_instr;
14261#else
14262 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
14263 for (n = count_instr; n > 0; n--) {
14264 *((duk_instr_t *) (void *) q) = DUK_RAW_READINC_U32_BE(p);
14265 q += sizeof(duk_instr_t);
14266 }
14267#endif
14268
14269 /* Load constants onto value stack but don't yet copy to buffer. */
14270 for (n = count_const; n > 0; n--) {
14271 DUK__ASSERT_LEFT(1);
14272 const_type = DUK_RAW_READINC_U8(p);
14273 switch (const_type) {
14274 case DUK__SER_STRING: {
14275 p = duk__load_string_raw(thr, p);
14276 break;
14277 }
14278 case DUK__SER_NUMBER: {
14279 /* Important to do a fastint check so that constants are
14280 * properly read back as fastints.
14281 */
14282 duk_tval tv_tmp;
14283 duk_double_t val;
14284 DUK__ASSERT_LEFT(8);
14285 val = DUK_RAW_READINC_DOUBLE_BE(p);
14286 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
14287 duk_push_tval(thr, &tv_tmp);
14288 break;
14289 }
14290 default: {
14291 goto format_error;
14292 }
14293 }
14294 }
14295
14296 /* Load inner functions to value stack, but don't yet copy to buffer. */
14297 for (n = count_funcs; n > 0; n--) {
14298 p = duk__load_func(thr, p, p_end);
14299 if (p == NULL) {
14300 goto format_error;
14301 }
14302 }
14303
14304 /* With constants and inner functions on value stack, we can now
14305 * atomically finish the function 'data' buffer, bump refcounts,
14306 * etc.
14307 *
14308 * Here we take advantage of the value stack being just a duk_tval
14309 * array: we can just memcpy() the constants as long as we incref
14310 * them afterwards.
14311 */
14312
14313 h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
14314 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
14315 DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
14316 DUK_HBUFFER_INCREF(thr, h_data);
14317
14318 tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */
14319 DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
14320
14321 q = fun_data;
14322 duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
14323 for (n = count_const; n > 0; n--) {
14324 DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
14325 q += sizeof(duk_tval);
14326 }
14327 tv1 += count_const;
14328
14329 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
14330 for (n = count_funcs; n > 0; n--) {
14331 duk_hobject *h_obj;
14332
14333 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
14334 h_obj = DUK_TVAL_GET_OBJECT(tv1);
14335 DUK_ASSERT(h_obj != NULL);
14336 tv1++;
14337 DUK_HOBJECT_INCREF(thr, h_obj);
14338
14339 *((duk_hobject **) (void *) q) = h_obj;
14340 q += sizeof(duk_hobject *);
14341 }
14342
14343 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
14344
14345 /* The function object is now reachable and refcounts are fine,
14346 * so we can pop off all the temporaries.
14347 */
14348 DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
14349 duk_set_top(thr, idx_base + 1);
14350
14351 /* Setup function properties. */
14352 tmp32 = DUK_RAW_READINC_U32_BE(p);
14353 duk_push_u32(thr, tmp32);
14354 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
14355
14356#if defined(DUK_USE_FUNC_NAME_PROPERTY)
14357 p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */
14358 func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
14359 DUK_ASSERT(func_env != NULL);
14360 need_pop = 0;
14361 if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
14362 /* Original function instance/template had NAMEBINDING.
14363 * Must create a lexical environment on loading to allow
14364 * recursive functions like 'function foo() { foo(); }'.
14365 */
14366 duk_hdecenv *new_env;
14367
14368 new_env = duk_hdecenv_alloc(thr,
14369 DUK_HOBJECT_FLAG_EXTENSIBLE |
14370 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
14371 DUK_ASSERT(new_env != NULL);
14372 DUK_ASSERT(new_env->thread == NULL); /* Closed. */
14373 DUK_ASSERT(new_env->varmap == NULL);
14374 DUK_ASSERT(new_env->regbase_byteoff == 0);
14375 DUK_HDECENV_ASSERT_VALID(new_env);
14376 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
14377 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
14378 DUK_HOBJECT_INCREF(thr, func_env);
14379
14380 func_env = (duk_hobject *) new_env;
14381
14382 duk_push_hobject(thr, (duk_hobject *) new_env);
14383
14384 duk_dup_m2(thr); /* -> [ func funcname env funcname ] */
14385 duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */
14386 duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
14387
14388 need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
14389 }
14390 DUK_ASSERT(func_env != NULL);
14391 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
14392 DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
14393 DUK_HOBJECT_INCREF(thr, func_env);
14394 DUK_HOBJECT_INCREF(thr, func_env);
14395 if (need_pop) {
14396 duk_pop(thr);
14397 }
14398 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
14399#endif /* DUK_USE_FUNC_NAME_PROPERTY */
14400
14401#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
14402 p = duk__load_string_raw(thr, p);
14403 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
14404#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
14405
14406 if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
14407 /* Restore empty external .prototype only for constructable
14408 * functions. The prototype object should inherit from
14409 * Object.prototype.
14410 */
14411 duk_push_object(thr);
14412 DUK_ASSERT(!duk_is_bare_object(thr, -1));
14413 duk_dup_m2(thr);
14414 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
14415 duk_compact_m1(thr);
14416 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
14417 }
14418
14419#if defined(DUK_USE_PC2LINE)
14420 p = duk__load_buffer_raw(thr, p);
14421 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
14422#endif /* DUK_USE_PC2LINE */
14423
14424 duk_push_bare_object(thr); /* _Varmap */
14425 for (;;) {
14426 /* XXX: awkward */
14427 p = duk__load_string_raw(thr, p);
14428 if (duk_get_length(thr, -1) == 0) {
14429 duk_pop(thr);
14430 break;
14431 }
14432 tmp32 = DUK_RAW_READINC_U32_BE(p);
14433 duk_push_u32(thr, tmp32);
14434 duk_put_prop(thr, -3);
14435 }
14436 duk_compact_m1(thr);
14437 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
14438
14439 /* _Formals may have been missing in the original function, which is
14440 * handled using a marker length.
14441 */
14442 arr_limit = DUK_RAW_READINC_U32_BE(p);
14443 if (arr_limit != DUK__NO_FORMALS) {
14444 duk_push_bare_array(thr); /* _Formals */
14445 for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
14446 p = duk__load_string_raw(thr, p);
14447 duk_put_prop_index(thr, -2, arr_idx);
14448 }
14449 duk_compact_m1(thr);
14450 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
14451 } else {
14452 DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
14453 }
14454
14455 /* Return with final function pushed on stack top. */
14456 DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
14457 DUK_ASSERT_TOP(thr, idx_base + 1);
14458 return p;
14459
14460 format_error:
14461 return NULL;
14462}
14463
14464DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
14465 duk_hcompfunc *func;
14466 duk_bufwriter_ctx bw_ctx_alloc;
14467 duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
14468 duk_uint8_t *p;
14469
14470 DUK_ASSERT_API_ENTRY(thr);
14471
14472 /* Bound functions don't have all properties so we'd either need to
14473 * lookup the non-bound target function or reject bound functions.
14474 * For now, bound functions are rejected with TypeError.
14475 */
14476 func = duk_require_hcompfunc(thr, -1);
14477 DUK_ASSERT(func != NULL);
14478 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
14479
14480 /* Estimating the result size beforehand would be costly, so
14481 * start with a reasonable size and extend as needed.
14482 */
14483 DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
14484 p = DUK_BW_GET_PTR(thr, bw_ctx);
14485 *p++ = DUK__SER_MARKER;
14486 p = duk__dump_func(thr, func, bw_ctx, p);
14487 DUK_BW_SET_PTR(thr, bw_ctx, p);
14488 DUK_BW_COMPACT(thr, bw_ctx);
14489
14490 DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
14491
14492 duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */
14493}
14494
14495DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
14496 const duk_uint8_t *p_buf, *p, *p_end;
14497 duk_size_t sz;
14498
14499 DUK_ASSERT_API_ENTRY(thr);
14500
14501 p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
14502 DUK_ASSERT(p_buf != NULL);
14503
14504 /* The caller is responsible for being sure that bytecode being loaded
14505 * is valid and trusted. Invalid bytecode can cause memory unsafe
14506 * behavior directly during loading or later during bytecode execution
14507 * (instruction validation would be quite complex to implement).
14508 *
14509 * This signature check is the only sanity check for detecting
14510 * accidental invalid inputs. The initial byte ensures no ordinary
14511 * string or Symbol will be accepted by accident.
14512 */
14513 p = p_buf;
14514 p_end = p_buf + sz;
14515 if (sz < 1 || p[0] != DUK__SER_MARKER) {
14516 goto format_error;
14517 }
14518 p++;
14519
14520 p = duk__load_func(thr, p, p_end);
14521 if (p == NULL) {
14522 goto format_error;
14523 }
14524
14525 duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */
14526 return;
14527
14528 format_error:
14529 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
14530 DUK_WO_NORETURN(return;);
14531}
14532
14533#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
14534
14535DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
14536 DUK_ASSERT_API_ENTRY(thr);
14537 DUK_ERROR_UNSUPPORTED(thr);
14538 DUK_WO_NORETURN(return;);
14539}
14540
14541DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
14542 DUK_ASSERT_API_ENTRY(thr);
14543 DUK_ERROR_UNSUPPORTED(thr);
14544 DUK_WO_NORETURN(return;);
14545}
14546
14547#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
14548
14549/* automatic undefs */
14550#undef DUK__ASSERT_LEFT
14551#undef DUK__BYTECODE_INITIAL_ALLOC
14552#undef DUK__NO_FORMALS
14553#undef DUK__SER_MARKER
14554#undef DUK__SER_NUMBER
14555#undef DUK__SER_STRING
14556#line 1 "duk_api_call.c"
14557/*
14558 * Calls.
14559 *
14560 * Protected variants should avoid ever throwing an error. Must be careful
14561 * to catch errors related to value stack manipulation and property lookup,
14562 * not just the call itself.
14563 *
14564 * The only exception is when arguments are insane, e.g. nargs/nrets are out
14565 * of bounds; in such cases an error is thrown for two reasons. First, we
14566 * can't always respect the value stack input/output guarantees in such cases
14567 * so the caller would end up with the value stack in an unexpected state.
14568 * Second, an attempt to create an error might itself fail (although this
14569 * could be avoided by pushing a preallocated object/string or a primitive
14570 * value).
14571 */
14572
14573/* #include duk_internal.h -> already included */
14574
14575/*
14576 * Helpers
14577 */
14578
14579struct duk__pcall_prop_args {
14580 duk_idx_t obj_idx;
14581 duk_idx_t nargs;
14582 duk_small_uint_t call_flags;
14583};
14584typedef struct duk__pcall_prop_args duk__pcall_prop_args;
14585
14586struct duk__pcall_method_args {
14587 duk_idx_t nargs;
14588 duk_small_uint_t call_flags;
14589};
14590typedef struct duk__pcall_method_args duk__pcall_method_args;
14591
14592struct duk__pcall_args {
14593 duk_idx_t nargs;
14594 duk_small_uint_t call_flags;
14595};
14596typedef struct duk__pcall_args duk__pcall_args;
14597
14598/* Compute and validate idx_func for a certain 'nargs' and 'other'
14599 * parameter count (1 or 2, depending on whether 'this' binding is
14600 * present).
14601 */
14602DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
14603 duk_idx_t idx_func;
14604
14605 /* XXX: byte arithmetic? */
14606
14607 DUK_ASSERT(other >= 0);
14608
14609 idx_func = duk_get_top(thr) - nargs - other;
14610 if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
14611 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14612 DUK_WO_NORETURN(return 0;);
14613 }
14614 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14615 return idx_func;
14616}
14617
14618/* Compute idx_func, assume index will be valid. This is a valid assumption
14619 * for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
14620 * validates the argument count.
14621 */
14622DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
14623 duk_idx_t idx_func;
14624
14625 /* XXX: byte arithmetic? */
14626
14627 DUK_ASSERT(nargs >= 0);
14628 DUK_ASSERT(other >= 0);
14629
14630 idx_func = duk_get_top(thr) - nargs - other;
14631 DUK_ASSERT(idx_func >= 0);
14632 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14633 return idx_func;
14634}
14635
14636/* Prepare value stack for a method call through an object property.
14637 * May currently throw an error e.g. when getting the property.
14638 */
14639DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
14640 DUK_CTX_ASSERT_VALID(thr);
14641 DUK_ASSERT(nargs >= 0);
14642
14643 DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
14644 (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
14645
14646 /* [... key arg1 ... argN] */
14647
14648 /* duplicate key */
14649 duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
14650 (void) duk_get_prop(thr, normalized_obj_idx);
14651
14652 DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
14653
14654#if defined(DUK_USE_VERBOSE_ERRORS)
14655 if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
14656 duk_tval *tv_base;
14657 duk_tval *tv_key;
14658
14659 /* tv_targ is passed on stack top (at index -1). */
14660 tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
14661 tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
14662 DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
14663 DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
14664
14665 duk_call_setup_propcall_error(thr, tv_base, tv_key);
14666 }
14667#endif
14668
14669 /* [... key arg1 ... argN func] */
14670
14671 duk_replace(thr, -nargs - 2);
14672
14673 /* [... func arg1 ... argN] */
14674
14675 duk_dup(thr, normalized_obj_idx);
14676 duk_insert(thr, -nargs - 1);
14677
14678 /* [... func this arg1 ... argN] */
14679}
14680
14681DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
14682 duk_small_uint_t call_flags;
14683 duk_idx_t idx_func;
14684
14685 DUK_ASSERT_API_ENTRY(thr);
14686
14687 idx_func = duk__call_get_idx_func(thr, nargs, 1);
14688 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14689
14690 duk_insert_undefined(thr, idx_func + 1);
14691
14692 call_flags = 0; /* not protected, respect reclimit, not constructor */
14693 duk_handle_call_unprotected(thr, idx_func, call_flags);
14694}
14695
14696DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
14697 duk_small_uint_t call_flags;
14698 duk_idx_t idx_func;
14699
14700 DUK_ASSERT_API_ENTRY(thr);
14701
14702 idx_func = duk__call_get_idx_func(thr, nargs, 2);
14703 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14704
14705 call_flags = 0; /* not protected, respect reclimit, not constructor */
14706 duk_handle_call_unprotected(thr, idx_func, call_flags);
14707}
14708
14709DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
14710 /*
14711 * XXX: if duk_handle_call() took values through indices, this could be
14712 * made much more sensible. However, duk_handle_call() needs to fudge
14713 * the 'this' and 'func' values to handle bound functions, which is now
14714 * done "in-place", so this is not a trivial change.
14715 */
14716
14717 DUK_ASSERT_API_ENTRY(thr);
14718
14719 obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
14720 if (DUK_UNLIKELY(nargs < 0)) {
14721 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14722 DUK_WO_NORETURN(return;);
14723 }
14724
14725 duk__call_prop_prep_stack(thr, obj_idx, nargs);
14726
14727 duk_call_method(thr, nargs);
14728}
14729
14730DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
14731 duk__pcall_args *args;
14732 duk_idx_t idx_func;
14733 duk_int_t ret;
14734
14735 DUK_CTX_ASSERT_VALID(thr);
14736 DUK_ASSERT(udata != NULL);
14737
14738 args = (duk__pcall_args *) udata;
14739 idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
14740 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14741
14742 duk_insert_undefined(thr, idx_func + 1);
14743
14744 ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
14745 DUK_ASSERT(ret == 0);
14746 DUK_UNREF(ret);
14747
14748 return 1;
14749}
14750
14751DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
14752 duk__pcall_args args;
14753
14754 DUK_ASSERT_API_ENTRY(thr);
14755
14756 args.nargs = nargs;
14757 if (DUK_UNLIKELY(nargs < 0)) {
14758 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14759 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14760 }
14761 args.call_flags = 0;
14762
14763 return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14764}
14765
14766DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
14767 duk__pcall_method_args *args;
14768 duk_idx_t idx_func;
14769 duk_int_t ret;
14770
14771 DUK_CTX_ASSERT_VALID(thr);
14772 DUK_ASSERT(udata != NULL);
14773
14774 args = (duk__pcall_method_args *) udata;
14775
14776 idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
14777 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14778
14779 ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
14780 DUK_ASSERT(ret == 0);
14781 DUK_UNREF(ret);
14782
14783 return 1;
14784}
14785
14786DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
14787 duk__pcall_method_args args;
14788
14789 DUK_ASSERT_API_ENTRY(thr);
14790
14791 args.nargs = nargs;
14792 if (DUK_UNLIKELY(nargs < 0)) {
14793 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14794 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14795 }
14796 args.call_flags = call_flags;
14797
14798 return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
14799}
14800
14801DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
14802 DUK_ASSERT_API_ENTRY(thr);
14803
14804 return duk_pcall_method_flags(thr, nargs, 0);
14805}
14806
14807DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
14808 duk__pcall_prop_args *args;
14809 duk_idx_t obj_idx;
14810 duk_int_t ret;
14811
14812 DUK_CTX_ASSERT_VALID(thr);
14813 DUK_ASSERT(udata != NULL);
14814
14815 args = (duk__pcall_prop_args *) udata;
14816
14817 obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */
14818 duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
14819
14820 ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
14821 DUK_ASSERT(ret == 0);
14822 DUK_UNREF(ret);
14823 return 1;
14824}
14825
14826DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
14827 duk__pcall_prop_args args;
14828
14829 DUK_ASSERT_API_ENTRY(thr);
14830
14831 args.obj_idx = obj_idx;
14832 args.nargs = nargs;
14833 if (DUK_UNLIKELY(nargs < 0)) {
14834 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14835 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14836 }
14837 args.call_flags = 0;
14838
14839 return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14840}
14841
14842DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
14843 duk_int_t rc;
14844
14845 DUK_ASSERT_API_ENTRY(thr);
14846
14847 /* nargs condition; fail if: top - bottom < nargs
14848 * <=> top < bottom + nargs
14849 * nrets condition; fail if: end - (top - nargs) < nrets
14850 * <=> end - top + nargs < nrets
14851 * <=> end + nargs < top + nrets
14852 */
14853 /* XXX: check for any reserve? */
14854
14855 if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */
14856 thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */
14857 thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */
14858 DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
14859 "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
14860 "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
14861 (long) nargs,
14862 (long) nrets,
14863 (long) (thr->valstack_top - thr->valstack),
14864 (long) (thr->valstack_bottom - thr->valstack),
14865 (long) nargs,
14866 (long) (thr->valstack_end - thr->valstack),
14867 (long) nargs,
14868 (long) (thr->valstack_top - thr->valstack),
14869 (long) nrets));
14870 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14871 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14872 }
14873
14874 rc = duk_handle_safe_call(thr, /* thread */
14875 func, /* func */
14876 udata, /* udata */
14877 nargs, /* num_stack_args */
14878 nrets); /* num_stack_res */
14879
14880 return rc;
14881}
14882
14883DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
14884 duk_idx_t idx_func;
14885
14886 DUK_ASSERT_API_ENTRY(thr);
14887
14888 idx_func = duk__call_get_idx_func(thr, nargs, 1);
14889 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14890
14891 duk_push_object(thr); /* default instance; internal proto updated by call handling */
14892 duk_insert(thr, idx_func + 1);
14893
14894 duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
14895}
14896
14897DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
14898 duk_idx_t nargs;
14899
14900 DUK_ASSERT(udata != NULL);
14901 nargs = *((duk_idx_t *) udata);
14902
14903 duk_new(thr, nargs);
14904 return 1;
14905}
14906
14907DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
14908 duk_int_t rc;
14909
14910 DUK_ASSERT_API_ENTRY(thr);
14911
14912 /* For now, just use duk_safe_call() to wrap duk_new(). We can't
14913 * simply use a protected duk_handle_call() because pushing the
14914 * default instance might throw.
14915 */
14916
14917 if (DUK_UNLIKELY(nargs < 0)) {
14918 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14919 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14920 }
14921
14922 rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14923 return rc;
14924}
14925
14926DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
14927 duk_activation *act;
14928
14929 DUK_ASSERT_API_ENTRY(thr);
14930
14931 act = thr->callstack_curr;
14932 if (act != NULL) {
14933 return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
14934 }
14935 return 0;
14936}
14937
14938DUK_EXTERNAL void duk_require_constructor_call(duk_hthread *thr) {
14939 DUK_ASSERT_API_ENTRY(thr);
14940
14941 if (!duk_is_constructor_call(thr)) {
14942 DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
14943 DUK_WO_NORETURN(return;);
14944 }
14945}
14946
14947DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
14948 duk_activation *act;
14949
14950 /* For user code this could just return 1 (strict) always
14951 * because all Duktape/C functions are considered strict,
14952 * and strict is also the default when nothing is running.
14953 * However, Duktape may call this function internally when
14954 * the current activation is an ECMAScript function, so
14955 * this cannot be replaced by a 'return 1' without fixing
14956 * the internal call sites.
14957 */
14958
14959 DUK_ASSERT_API_ENTRY(thr);
14960
14961 act = thr->callstack_curr;
14962 if (act != NULL) {
14963 return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
14964 } else {
14965 /* Strict by default. */
14966 return 1;
14967 }
14968}
14969
14970/*
14971 * Duktape/C function magic
14972 */
14973
14974DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
14975 duk_activation *act;
14976 duk_hobject *func;
14977
14978 DUK_ASSERT_API_ENTRY(thr);
14979
14980 act = thr->callstack_curr;
14981 if (act) {
14982 func = DUK_ACT_GET_FUNC(act);
14983 if (!func) {
14984 duk_tval *tv = &act->tv_func;
14985 duk_small_uint_t lf_flags;
14986 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
14987 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
14988 }
14989 DUK_ASSERT(func != NULL);
14990
14991 if (DUK_HOBJECT_IS_NATFUNC(func)) {
14992 duk_hnatfunc *nf = (duk_hnatfunc *) func;
14993 return (duk_int_t) nf->magic;
14994 }
14995 }
14996 return 0;
14997}
14998
14999DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
15000 duk_tval *tv;
15001 duk_hobject *h;
15002
15003 DUK_ASSERT_API_ENTRY(thr);
15004
15005 tv = duk_require_tval(thr, idx);
15006 if (DUK_TVAL_IS_OBJECT(tv)) {
15007 h = DUK_TVAL_GET_OBJECT(tv);
15008 DUK_ASSERT(h != NULL);
15009 if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
15010 goto type_error;
15011 }
15012 return (duk_int_t) ((duk_hnatfunc *) h)->magic;
15013 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
15014 duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
15015 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
15016 }
15017
15018 /* fall through */
15019 type_error:
15020 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
15021 DUK_WO_NORETURN(return 0;);
15022}
15023
15024DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
15025 duk_hnatfunc *nf;
15026
15027 DUK_ASSERT_API_ENTRY(thr);
15028
15029 nf = duk_require_hnatfunc(thr, idx);
15030 DUK_ASSERT(nf != NULL);
15031 nf->magic = (duk_int16_t) magic;
15032}
15033
15034/*
15035 * Misc helpers
15036 */
15037
15038/* Resolve a bound function on value stack top to a non-bound target
15039 * (leave other values as is).
15040 */
15041DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
15042 duk_tval *tv;
15043
15044 DUK_HTHREAD_ASSERT_VALID(thr);
15045
15046 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
15047 if (DUK_TVAL_IS_OBJECT(tv)) {
15048 duk_hobject *h;
15049
15050 h = DUK_TVAL_GET_OBJECT(tv);
15051 DUK_ASSERT(h != NULL);
15052 if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
15053 duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target);
15054 duk_replace(thr, -2);
15055#if 0
15056 DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
15057 DUK_TVAL_INCREF(thr, tv);
15058 DUK_HOBJECT_DECREF_NORZ(thr, h);
15059#endif
15060 /* Rely on Function.prototype.bind() on never creating a bound
15061 * function whose target is not proper. This is now safe
15062 * because the target is not even an internal property but a
15063 * struct member.
15064 */
15065 DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
15066 }
15067 }
15068
15069 /* Lightfuncs cannot be bound but are always callable and
15070 * constructable.
15071 */
15072}
15073#line 1 "duk_api_codec.c"
15074/*
15075 * Encoding and decoding basic formats: hex, base64.
15076 *
15077 * These are in-place operations which may allow an optimized implementation.
15078 *
15079 * Base-64: https://tools.ietf.org/html/rfc4648#section-4
15080 */
15081
15082/* #include duk_internal.h -> already included */
15083
15084/*
15085 * Misc helpers
15086 */
15087
15088/* Shared handling for encode/decode argument. Fast path handling for
15089 * buffer and string values because they're the most common. In particular,
15090 * avoid creating a temporary string or buffer when possible. Return value
15091 * is guaranteed to be non-NULL, even for zero length input.
15092 */
15093DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
15094 const void *def_ptr = (const void *) out_len; /* Any non-NULL pointer will do. */
15095 const void *ptr;
15096 duk_bool_t isbuffer;
15097
15098 DUK_ASSERT(out_len != NULL);
15099 DUK_ASSERT(def_ptr != NULL);
15100 DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */
15101
15102 ptr = (const void *) duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
15103 if (isbuffer) {
15104 DUK_ASSERT(ptr != NULL || *out_len == 0U);
15105 if (DUK_UNLIKELY(ptr == NULL)) {
15106 ptr = def_ptr;
15107 }
15108 DUK_ASSERT(ptr != NULL);
15109 } else {
15110 /* For strings a non-NULL pointer is always guaranteed because
15111 * at least a NUL will be present.
15112 */
15113 ptr = (const void *) duk_to_lstring(thr, idx, out_len);
15114 DUK_ASSERT(ptr != NULL);
15115 }
15116 DUK_ASSERT(ptr != NULL);
15117 return (const duk_uint8_t *) ptr;
15118}
15119
15120/*
15121 * Base64
15122 */
15123
15124#if defined(DUK_USE_BASE64_SUPPORT)
15125/* Bytes emitted for number of padding characters in range [0,4]. */
15126DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = {
15127 3, /* #### -> 24 bits, emit 3 bytes */
15128 2, /* ###= -> 18 bits, emit 2 bytes */
15129 1, /* ##== -> 12 bits, emit 1 byte */
15130 -1, /* #=== -> 6 bits, error */
15131 0, /* ==== -> 0 bits, emit 0 bytes */
15132};
15133
15134#if defined(DUK_USE_BASE64_FASTPATH)
15135DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = {
15136 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, /* A...P */
15137 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, /* Q...f */
15138 0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, /* g...v */
15139 0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU /* w.../ */
15140};
15141#endif /* DUK_USE_BASE64_FASTPATH */
15142
15143#if defined(DUK_USE_BASE64_FASTPATH)
15144/* Decode table for one byte of input:
15145 * -1 = allowed whitespace
15146 * -2 = padding
15147 * -3 = error
15148 * 0...63 decoded bytes
15149 */
15150DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = {
15151 -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00...0x0f */
15152 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10...0x1f */
15153 -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63, /* 0x20...0x2f */
15154 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3, /* 0x30...0x3f */
15155 -3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
15156 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3, /* 0x50...0x5f */
15157 -3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
15158 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3, /* 0x70...0x7f */
15159 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80...0x8f */
15160 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90...0x9f */
15161 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0...0xaf */
15162 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0...0xbf */
15163 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0...0xcf */
15164 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0...0xdf */
15165 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0...0xef */
15166 -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0...0xff */
15167};
15168#endif /* DUK_USE_BASE64_FASTPATH */
15169
15170#if defined(DUK_USE_BASE64_FASTPATH)
15171DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) {
15172 duk_uint_t t;
15173
15174 t = (duk_uint_t) src[0];
15175 t = (t << 8) + (duk_uint_t) src[1];
15176 t = (t << 8) + (duk_uint_t) src[2];
15177
15178 dst[0] = duk__base64_enctab_fast[t >> 18];
15179 dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU];
15180 dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU];
15181 dst[3] = duk__base64_enctab_fast[t & 0x3fU];
15182
15183#if 0
15184 /* Tested: not faster on x64, most likely due to aliasing between
15185 * output and input index computation.
15186 */
15187 /* aaaaaabb bbbbcccc ccdddddd */
15188 dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU];
15189 dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)];
15190 dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)];
15191 dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU];
15192#endif
15193}
15194
15195DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) {
15196 duk_uint_t t;
15197
15198 t = (duk_uint_t) src[0];
15199 t = (t << 8) + (duk_uint_t) src[1];
15200 dst[0] = duk__base64_enctab_fast[t >> 10]; /* XXXXXX-- -------- */
15201 dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU]; /* ------XX XXXX---- */
15202 dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU]; /* -------- ----XXXX */
15203 dst[3] = DUK_ASC_EQUALS;
15204}
15205
15206DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) {
15207 duk_uint_t t;
15208
15209 t = (duk_uint_t) src[0];
15210 dst[0] = duk__base64_enctab_fast[t >> 2]; /* XXXXXX-- */
15211 dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU]; /* ------XX */
15212 dst[2] = DUK_ASC_EQUALS;
15213 dst[3] = DUK_ASC_EQUALS;
15214}
15215
15216DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
15217 duk_size_t n;
15218 const duk_uint8_t *p;
15219 duk_uint8_t *q;
15220
15221 n = srclen;
15222 p = src;
15223 q = dst;
15224
15225 if (n >= 16U) {
15226 /* Fast path, unrolled by 4, allows interleaving. Process
15227 * 12-byte input chunks which encode to 16-char output chunks.
15228 * Only enter when at least one block is emitted (avoids div+mul
15229 * for short inputs too).
15230 */
15231 const duk_uint8_t *p_end_fast;
15232
15233 p_end_fast = p + ((n / 12U) * 12U);
15234 DUK_ASSERT(p_end_fast >= p + 12);
15235 do {
15236 duk__base64_encode_fast_3(p, q);
15237 duk__base64_encode_fast_3(p + 3, q + 4);
15238 duk__base64_encode_fast_3(p + 6, q + 8);
15239 duk__base64_encode_fast_3(p + 9, q + 12);
15240 p += 12;
15241 q += 16;
15242 } while (DUK_LIKELY(p != p_end_fast));
15243
15244 DUK_ASSERT(src + srclen >= p);
15245 n = (duk_size_t) (src + srclen - p);
15246 DUK_ASSERT(n < 12U);
15247 }
15248
15249 /* Remainder. */
15250 while (n >= 3U) {
15251 duk__base64_encode_fast_3(p, q);
15252 p += 3;
15253 q += 4;
15254 n -= 3U;
15255 }
15256 DUK_ASSERT(n == 0U || n == 1U || n == 2U);
15257 if (n == 1U) {
15258 duk__base64_encode_fast_1(p, q);
15259#if 0 /* Unnecessary. */
15260 p += 1;
15261 q += 4;
15262 n -= 1U;
15263#endif
15264 } else if (n == 2U) {
15265 duk__base64_encode_fast_2(p, q);
15266#if 0 /* Unnecessary. */
15267 p += 2;
15268 q += 4;
15269 n -= 2U;
15270#endif
15271 } else {
15272 DUK_ASSERT(n == 0U); /* nothing to do */
15273 ;
15274 }
15275}
15276#else /* DUK_USE_BASE64_FASTPATH */
15277DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
15278 duk_small_uint_t i, npad;
15279 duk_uint_t t, x, y;
15280 const duk_uint8_t *p;
15281 const duk_uint8_t *p_end;
15282 duk_uint8_t *q;
15283
15284 p = src;
15285 p_end = src + srclen;
15286 q = dst;
15287 npad = 0U;
15288
15289 while (p < p_end) {
15290 /* Read 3 bytes into 't', padded by zero. */
15291 t = 0;
15292 for (i = 0; i < 3; i++) {
15293 t = t << 8;
15294 if (p < p_end) {
15295 t += (duk_uint_t) (*p++);
15296 } else {
15297 /* This only happens on the last loop and we're
15298 * guaranteed to exit on the next loop.
15299 */
15300 npad++;
15301 }
15302 }
15303 DUK_ASSERT(npad <= 2U);
15304
15305 /* Emit 4 encoded characters. If npad > 0, some of the
15306 * chars will be incorrect (zero bits) but we fix up the
15307 * padding after the loop. A straightforward 64-byte
15308 * lookup would be faster and cleaner, but this is shorter.
15309 */
15310 for (i = 0; i < 4; i++) {
15311 x = ((t >> 18) & 0x3fU);
15312 t = t << 6;
15313
15314 if (x <= 51U) {
15315 if (x <= 25) {
15316 y = x + DUK_ASC_UC_A;
15317 } else {
15318 y = x - 26 + DUK_ASC_LC_A;
15319 }
15320 } else {
15321 if (x <= 61U) {
15322 y = x - 52 + DUK_ASC_0;
15323 } else if (x == 62) {
15324 y = DUK_ASC_PLUS;
15325 } else {
15326 DUK_ASSERT(x == 63);
15327 y = DUK_ASC_SLASH;
15328 }
15329 }
15330
15331 *q++ = (duk_uint8_t) y;
15332 }
15333 }
15334
15335 /* Handle padding by rewriting 0-2 bogus characters at the end.
15336 *
15337 * Missing bytes npad base64 example
15338 * 0 0 ####
15339 * 1 1 ###=
15340 * 2 2 ##==
15341 */
15342 DUK_ASSERT(npad <= 2U);
15343 while (npad > 0U) {
15344 *(q - npad) = DUK_ASC_EQUALS;
15345 npad--;
15346 }
15347}
15348#endif /* DUK_USE_BASE64_FASTPATH */
15349
15350#if defined(DUK_USE_BASE64_FASTPATH)
15351DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
15352 duk_int_t x;
15353 duk_uint_t t;
15354 duk_small_uint_t n_equal;
15355 duk_int8_t step;
15356 const duk_uint8_t *p;
15357 const duk_uint8_t *p_end;
15358 const duk_uint8_t *p_end_safe;
15359 duk_uint8_t *q;
15360
15361 DUK_ASSERT(src != NULL); /* Required by pointer arithmetic below, which fails for NULL. */
15362
15363 p = src;
15364 p_end = src + srclen;
15365 p_end_safe = p_end - 8; /* If 'src <= src_end_safe', safe to read 8 bytes. */
15366 q = dst;
15367
15368 /* Alternate between a fast path which processes clean groups with no
15369 * padding or whitespace, and a slow path which processes one arbitrary
15370 * group and then re-enters the fast path. This handles e.g. base64
15371 * with newlines reasonably well because the majority of a line is in
15372 * the fast path.
15373 */
15374 for (;;) {
15375 /* Fast path, on each loop handle two 4-char input groups.
15376 * If both are clean, emit 6 bytes and continue. If first
15377 * is clean, emit 3 bytes and drop out; otherwise emit
15378 * nothing and drop out. This approach could be extended to
15379 * more groups per loop, but for inputs with e.g. periodic
15380 * newlines (which are common) it might not be an improvement.
15381 */
15382 while (DUK_LIKELY(p <= p_end_safe)) {
15383 duk_int_t t1, t2;
15384
15385 /* The lookup byte is intentionally sign extended to
15386 * (at least) 32 bits and then ORed. This ensures
15387 * that is at least 1 byte is negative, the highest
15388 * bit of the accumulator will be set at the end and
15389 * we don't need to check every byte.
15390 *
15391 * Read all input bytes first before writing output
15392 * bytes to minimize aliasing.
15393 */
15394 DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p",
15395 (const void *) p, (const void *) p_end_safe, (const void *) p_end));
15396
15397 t1 = (duk_int_t) duk__base64_dectab_fast[p[0]];
15398 t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]];
15399 t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]];
15400 t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]];
15401
15402 t2 = (duk_int_t) duk__base64_dectab_fast[p[4]];
15403 t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]];
15404 t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]];
15405 t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]];
15406
15407 q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU);
15408 q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU);
15409 q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU);
15410
15411 q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU);
15412 q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU);
15413 q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU);
15414
15415 /* Optimistic check using one branch. */
15416 if (DUK_LIKELY((t1 | t2) >= 0)) {
15417 p += 8;
15418 q += 6;
15419 } else if (t1 >= 0) {
15420 DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group"));
15421 DUK_ASSERT(t2 < 0);
15422 p += 4;
15423 q += 3;
15424 break;
15425 } else {
15426 DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group"));
15427 DUK_ASSERT(t1 < 0);
15428 break;
15429 }
15430 } /* fast path */
15431
15432 /* Slow path step 1: try to scan a 4-character encoded group,
15433 * end-of-input, or start-of-padding. We exit with:
15434 * 1. n_chars == 4: full group, no padding, no end-of-input.
15435 * 2. n_chars < 4: partial group (may also be 0), encountered
15436 * padding or end of input.
15437 *
15438 * The accumulator is initialized to 1; this allows us to detect
15439 * a full group by comparing >= 0x1000000 without an extra
15440 * counter variable.
15441 */
15442 t = 1UL;
15443 for (;;) {
15444 DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu",
15445 (const void *) p, (const void *) p_end, (unsigned long) t));
15446
15447 if (DUK_LIKELY(p < p_end)) {
15448 x = duk__base64_dectab_fast[*p++];
15449 if (DUK_LIKELY(x >= 0)) {
15450 DUK_ASSERT(x >= 0 && x <= 63);
15451 t = (t << 6) + (duk_uint_t) x;
15452 if (t >= 0x1000000UL) {
15453 break;
15454 }
15455 } else if (x == -1) {
15456 continue; /* allowed ascii whitespace */
15457 } else if (x == -2) {
15458 p--;
15459 break; /* start of padding */
15460 } else {
15461 DUK_ASSERT(x == -3);
15462 goto decode_error;
15463 }
15464 } else {
15465 break; /* end of input */
15466 }
15467 } /* slow path step 1 */
15468
15469 /* Complete the padding by simulating pad characters,
15470 * regardless of actual input padding chars.
15471 */
15472 n_equal = 0;
15473 while (t < 0x1000000UL) {
15474 t = (t << 6) + 0U;
15475 n_equal++;
15476 }
15477
15478 /* Slow path step 2: deal with full/partial group, padding,
15479 * etc. Note that for num chars in [0,3] we intentionally emit
15480 * 3 bytes but don't step forward that much, buffer space is
15481 * guaranteed in setup.
15482 *
15483 * num chars:
15484 * 0 #### no output (= step 0)
15485 * 1 #=== reject, 6 bits of data
15486 * 2 ##== 12 bits of data, output 1 byte (= step 1)
15487 * 3 ###= 18 bits of data, output 2 bytes (= step 2)
15488 * 4 #### 24 bits of data, output 3 bytes (= step 3)
15489 */
15490 q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
15491 q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
15492 q[2] = (duk_uint8_t) (t & 0xffU);
15493
15494 DUK_ASSERT(n_equal <= 4);
15495 step = duk__base64_decode_nequal_step[n_equal];
15496 if (DUK_UNLIKELY(step < 0)) {
15497 goto decode_error;
15498 }
15499 q += step;
15500
15501 /* Slow path step 3: read and ignore padding and whitespace
15502 * until (a) next non-padding and non-whitespace character
15503 * after which we resume the fast path, or (b) end of input.
15504 * This allows us to accept missing, partial, full, and extra
15505 * padding cases uniformly. We also support concatenated
15506 * base-64 documents because we resume scanning afterwards.
15507 *
15508 * Note that to support concatenated documents well, the '='
15509 * padding found inside the input must also allow for 'extra'
15510 * padding. For example, 'Zm===' decodes to 'f' and has one
15511 * extra padding char. So, 'Zm===Zm' should decode 'ff', even
15512 * though the standard break-up would be 'Zm==' + '=Zm' which
15513 * doesn't make sense.
15514 *
15515 * We also accept prepended padding like '==Zm9', because it
15516 * is equivalent to an empty document with extra padding ('==')
15517 * followed by a valid document.
15518 */
15519
15520 for (;;) {
15521 if (DUK_UNLIKELY(p >= p_end)) {
15522 goto done;
15523 }
15524 x = duk__base64_dectab_fast[*p++];
15525 if (x == -1 || x == -2) {
15526 ; /* padding or whitespace, keep eating */
15527 } else {
15528 p--;
15529 break; /* backtrack and go back to fast path, even for -1 */
15530 }
15531 } /* slow path step 3 */
15532 } /* outer fast+slow path loop */
15533
15534 done:
15535 DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p",
15536 (const void *) p, (const void *) p_end));
15537
15538 DUK_ASSERT(p == p_end);
15539
15540 *out_dst_final = q;
15541 return 1;
15542
15543 decode_error:
15544 return 0;
15545}
15546#else /* DUK_USE_BASE64_FASTPATH */
15547DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
15548 duk_uint_t t, x;
15549 duk_int_t y;
15550 duk_int8_t step;
15551 const duk_uint8_t *p;
15552 const duk_uint8_t *p_end;
15553 duk_uint8_t *q;
15554 /* 0x09, 0x0a, or 0x0d */
15555 duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13);
15556
15557 /* 't' tracks progress of the decoded group:
15558 *
15559 * t == 1 no valid chars yet
15560 * t >= 0x40 1x6 = 6 bits shifted in
15561 * t >= 0x1000 2x6 = 12 bits shifted in
15562 * t >= 0x40000 3x6 = 18 bits shifted in
15563 * t >= 0x1000000 4x6 = 24 bits shifted in
15564 *
15565 * By initializing t=1 there's no need for a separate counter for
15566 * the number of characters found so far.
15567 */
15568 p = src;
15569 p_end = src + srclen;
15570 q = dst;
15571 t = 1UL;
15572
15573 for (;;) {
15574 duk_small_uint_t n_equal;
15575
15576 DUK_ASSERT(t >= 1U);
15577 if (p >= p_end) {
15578 /* End of input: if input exists, treat like
15579 * start of padding, finish the block, then
15580 * re-enter here to see we're done.
15581 */
15582 if (t == 1U) {
15583 break;
15584 } else {
15585 goto simulate_padding;
15586 }
15587 }
15588
15589 x = *p++;
15590
15591 if (x >= 0x41U) {
15592 /* Valid: a-z and A-Z. */
15593 DUK_ASSERT(x >= 0x41U && x <= 0xffU);
15594 if (x >= 0x61U && x <= 0x7aU) {
15595 y = (duk_int_t) x - 0x61 + 26;
15596 } else if (x <= 0x5aU) {
15597 y = (duk_int_t) x - 0x41;
15598 } else {
15599 goto decode_error;
15600 }
15601 } else if (x >= 0x30U) {
15602 /* Valid: 0-9 and =. */
15603 DUK_ASSERT(x >= 0x30U && x <= 0x40U);
15604 if (x <= 0x39U) {
15605 y = (duk_int_t) x - 0x30 + 52;
15606 } else if (x == 0x3dU) {
15607 /* Skip padding and whitespace unless we're in the
15608 * middle of a block. Otherwise complete group by
15609 * simulating shifting in the correct padding.
15610 */
15611 if (t == 1U) {
15612 continue;
15613 }
15614 goto simulate_padding;
15615 } else {
15616 goto decode_error;
15617 }
15618 } else if (x >= 0x20U) {
15619 /* Valid: +, /, and 0x20 whitespace. */
15620 DUK_ASSERT(x >= 0x20U && x <= 0x2fU);
15621 if (x == 0x2bU) {
15622 y = 62;
15623 } else if (x == 0x2fU) {
15624 y = 63;
15625 } else if (x == 0x20U) {
15626 continue;
15627 } else {
15628 goto decode_error;
15629 }
15630 } else {
15631 /* Valid: whitespace. */
15632 duk_uint32_t m;
15633 DUK_ASSERT(x < 0x20U); /* 0x00 to 0x1f */
15634 m = (1U << x);
15635 if (mask_white & m) {
15636 /* Allow basic ASCII whitespace. */
15637 continue;
15638 } else {
15639 goto decode_error;
15640 }
15641 }
15642
15643 DUK_ASSERT(y >= 0 && y <= 63);
15644 t = (t << 6) + (duk_uint_t) y;
15645 if (t < 0x1000000UL) {
15646 continue;
15647 }
15648 /* fall through; no padding will be added */
15649
15650 simulate_padding:
15651 n_equal = 0;
15652 while (t < 0x1000000UL) {
15653 t = (t << 6) + 0U;
15654 n_equal++;
15655 }
15656
15657 /* Output 3 bytes from 't' and advance as needed. */
15658 q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
15659 q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
15660 q[2] = (duk_uint8_t) (t & 0xffU);
15661
15662 DUK_ASSERT(n_equal <= 4U);
15663 step = duk__base64_decode_nequal_step[n_equal];
15664 if (step < 0) {
15665 goto decode_error;
15666 }
15667 q += step;
15668
15669 /* Re-enter loop. The actual padding characters are skipped
15670 * by the main loop. This handles cases like missing, partial,
15671 * full, and extra padding, and allows parsing of concatenated
15672 * documents (with extra padding) like: Zm===Zm. Also extra
15673 * prepended padding is accepted: ===Zm9v.
15674 */
15675 t = 1U;
15676 }
15677 DUK_ASSERT(t == 1UL);
15678
15679 *out_dst_final = q;
15680 return 1;
15681
15682 decode_error:
15683 return 0;
15684}
15685#endif /* DUK_USE_BASE64_FASTPATH */
15686
15687DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
15688 const duk_uint8_t *src;
15689 duk_size_t srclen;
15690 duk_size_t dstlen;
15691 duk_uint8_t *dst;
15692 const char *ret;
15693
15694 DUK_ASSERT_API_ENTRY(thr);
15695
15696 idx = duk_require_normalize_index(thr, idx);
15697 src = duk__prep_codec_arg(thr, idx, &srclen);
15698 DUK_ASSERT(src != NULL);
15699
15700 /* Compute exact output length. Computation must not wrap; this
15701 * limit works for 32-bit size_t:
15702 * >>> srclen = 3221225469
15703 * >>> '%x' % ((srclen + 2) / 3 * 4)
15704 * 'fffffffc'
15705 */
15706 if (srclen > 3221225469UL) {
15707 goto type_error;
15708 }
15709 dstlen = (srclen + 2U) / 3U * 4U;
15710 dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
15711
15712 duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
15713
15714 ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
15715 duk_replace(thr, idx);
15716 return ret;
15717
15718 type_error:
15719 DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
15720 DUK_WO_NORETURN(return NULL;);
15721}
15722
15723DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
15724 const duk_uint8_t *src;
15725 duk_size_t srclen;
15726 duk_size_t dstlen;
15727 duk_uint8_t *dst;
15728 duk_uint8_t *dst_final;
15729
15730 DUK_ASSERT_API_ENTRY(thr);
15731
15732 idx = duk_require_normalize_index(thr, idx);
15733 src = duk__prep_codec_arg(thr, idx, &srclen);
15734 DUK_ASSERT(src != NULL);
15735
15736 /* Round up and add safety margin. Avoid addition before division to
15737 * avoid possibility of wrapping. Margin includes +3 for rounding up,
15738 * and +3 for one extra group: the decoder may emit and then backtrack
15739 * a full group (3 bytes) from zero-sized input for technical reasons.
15740 * Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then
15741 * backtracked.
15742 */
15743 dstlen = (srclen / 4) * 3 + 6; /* upper limit, assuming no whitespace etc */
15744 dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
15745 /* Note: for dstlen=0, dst may be NULL */
15746
15747 if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) {
15748 goto type_error;
15749 }
15750
15751 /* XXX: convert to fixed buffer? */
15752 (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
15753 duk_replace(thr, idx);
15754 return;
15755
15756 type_error:
15757 DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
15758 DUK_WO_NORETURN(return;);
15759}
15760#else /* DUK_USE_BASE64_SUPPORT */
15761DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
15762 DUK_UNREF(idx);
15763 DUK_ERROR_UNSUPPORTED(thr);
15764 DUK_WO_NORETURN(return NULL;);
15765}
15766
15767DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
15768 DUK_UNREF(idx);
15769 DUK_ERROR_UNSUPPORTED(thr);
15770 DUK_WO_NORETURN(return;);
15771}
15772#endif /* DUK_USE_BASE64_SUPPORT */
15773
15774/*
15775 * Hex
15776 */
15777
15778#if defined(DUK_USE_HEX_SUPPORT)
15779DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
15780 const duk_uint8_t *inp;
15781 duk_size_t len;
15782 duk_size_t i;
15783 duk_uint8_t *buf;
15784 const char *ret;
15785#if defined(DUK_USE_HEX_FASTPATH)
15786 duk_size_t len_safe;
15787 duk_uint16_t *p16;
15788#endif
15789
15790 DUK_ASSERT_API_ENTRY(thr);
15791
15792 idx = duk_require_normalize_index(thr, idx);
15793 inp = duk__prep_codec_arg(thr, idx, &len);
15794 DUK_ASSERT(inp != NULL);
15795
15796 /* Fixed buffer, no zeroing because we'll fill all the data. */
15797 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
15798 DUK_ASSERT(buf != NULL);
15799
15800#if defined(DUK_USE_HEX_FASTPATH)
15801 DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
15802 p16 = (duk_uint16_t *) (void *) buf;
15803 len_safe = len & ~0x03U;
15804 for (i = 0; i < len_safe; i += 4) {
15805 p16[0] = duk_hex_enctab[inp[i]];
15806 p16[1] = duk_hex_enctab[inp[i + 1]];
15807 p16[2] = duk_hex_enctab[inp[i + 2]];
15808 p16[3] = duk_hex_enctab[inp[i + 3]];
15809 p16 += 4;
15810 }
15811 for (; i < len; i++) {
15812 *p16++ = duk_hex_enctab[inp[i]];
15813 }
15814#else /* DUK_USE_HEX_FASTPATH */
15815 for (i = 0; i < len; i++) {
15816 duk_small_uint_t t;
15817 t = (duk_small_uint_t) inp[i];
15818 buf[i*2 + 0] = duk_lc_digits[t >> 4];
15819 buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
15820 }
15821#endif /* DUK_USE_HEX_FASTPATH */
15822
15823 /* XXX: Using a string return value forces a string intern which is
15824 * not always necessary. As a rough performance measure, hex encode
15825 * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
15826 * without string coercion. Change to returning a buffer and let the
15827 * caller coerce to string if necessary?
15828 */
15829
15830 ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
15831 duk_replace(thr, idx);
15832 return ret;
15833}
15834
15835DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
15836 const duk_uint8_t *inp;
15837 duk_size_t len;
15838 duk_size_t i;
15839 duk_int_t t;
15840 duk_uint8_t *buf;
15841#if defined(DUK_USE_HEX_FASTPATH)
15842 duk_int_t chk;
15843 duk_uint8_t *p;
15844 duk_size_t len_safe;
15845#endif
15846
15847 DUK_ASSERT_API_ENTRY(thr);
15848
15849 idx = duk_require_normalize_index(thr, idx);
15850 inp = duk__prep_codec_arg(thr, idx, &len);
15851 DUK_ASSERT(inp != NULL);
15852
15853 if (len & 0x01) {
15854 goto type_error;
15855 }
15856
15857 /* Fixed buffer, no zeroing because we'll fill all the data. */
15858 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
15859 DUK_ASSERT(buf != NULL);
15860
15861#if defined(DUK_USE_HEX_FASTPATH)
15862 p = buf;
15863 len_safe = len & ~0x07U;
15864 for (i = 0; i < len_safe; i += 8) {
15865 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
15866 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
15867 chk = t;
15868 p[0] = (duk_uint8_t) t;
15869 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
15870 ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
15871 chk |= t;
15872 p[1] = (duk_uint8_t) t;
15873 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
15874 ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
15875 chk |= t;
15876 p[2] = (duk_uint8_t) t;
15877 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
15878 ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
15879 chk |= t;
15880 p[3] = (duk_uint8_t) t;
15881 p += 4;
15882
15883 /* Check if any lookup above had a negative result. */
15884 if (DUK_UNLIKELY(chk < 0)) {
15885 goto type_error;
15886 }
15887 }
15888 for (; i < len; i += 2) {
15889 /* First cast to duk_int_t to sign extend, second cast to
15890 * duk_uint_t to avoid signed left shift, and final cast to
15891 * duk_int_t result type.
15892 */
15893 t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
15894 ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
15895 if (DUK_UNLIKELY(t < 0)) {
15896 goto type_error;
15897 }
15898 *p++ = (duk_uint8_t) t;
15899 }
15900#else /* DUK_USE_HEX_FASTPATH */
15901 for (i = 0; i < len; i += 2) {
15902 /* For invalid characters the value -1 gets extended to
15903 * at least 16 bits. If either nybble is invalid, the
15904 * resulting 't' will be < 0.
15905 */
15906 t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
15907 ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
15908 if (DUK_UNLIKELY(t < 0)) {
15909 goto type_error;
15910 }
15911 buf[i >> 1] = (duk_uint8_t) t;
15912 }
15913#endif /* DUK_USE_HEX_FASTPATH */
15914
15915 duk_replace(thr, idx);
15916 return;
15917
15918 type_error:
15919 DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
15920 DUK_WO_NORETURN(return;);
15921}
15922#else /* DUK_USE_HEX_SUPPORT */
15923DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
15924 DUK_UNREF(idx);
15925 DUK_ERROR_UNSUPPORTED(thr);
15926 DUK_WO_NORETURN(return NULL;);
15927}
15928DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
15929 DUK_UNREF(idx);
15930 DUK_ERROR_UNSUPPORTED(thr);
15931 DUK_WO_NORETURN(return;);
15932}
15933#endif /* DUK_USE_HEX_SUPPORT */
15934
15935/*
15936 * JSON
15937 */
15938
15939#if defined(DUK_USE_JSON_SUPPORT)
15940DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
15941#if defined(DUK_USE_ASSERTIONS)
15942 duk_idx_t top_at_entry;
15943#endif
15944 const char *ret;
15945
15946 DUK_ASSERT_API_ENTRY(thr);
15947#if defined(DUK_USE_ASSERTIONS)
15948 top_at_entry = duk_get_top(thr);
15949#endif
15950
15951 idx = duk_require_normalize_index(thr, idx);
15952 duk_bi_json_stringify_helper(thr,
15953 idx /*idx_value*/,
15954 DUK_INVALID_INDEX /*idx_replacer*/,
15955 DUK_INVALID_INDEX /*idx_space*/,
15956 0 /*flags*/);
15957 DUK_ASSERT(duk_is_string(thr, -1));
15958 duk_replace(thr, idx);
15959 ret = duk_get_string(thr, idx);
15960
15961 DUK_ASSERT(duk_get_top(thr) == top_at_entry);
15962
15963 return ret;
15964}
15965
15966DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
15967#if defined(DUK_USE_ASSERTIONS)
15968 duk_idx_t top_at_entry;
15969#endif
15970
15971 DUK_ASSERT_API_ENTRY(thr);
15972#if defined(DUK_USE_ASSERTIONS)
15973 top_at_entry = duk_get_top(thr);
15974#endif
15975
15976 idx = duk_require_normalize_index(thr, idx);
15977 duk_bi_json_parse_helper(thr,
15978 idx /*idx_value*/,
15979 DUK_INVALID_INDEX /*idx_reviver*/,
15980 0 /*flags*/);
15981 duk_replace(thr, idx);
15982
15983 DUK_ASSERT(duk_get_top(thr) == top_at_entry);
15984}
15985#else /* DUK_USE_JSON_SUPPORT */
15986DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
15987 DUK_ASSERT_API_ENTRY(thr);
15988 DUK_UNREF(idx);
15989 DUK_ERROR_UNSUPPORTED(thr);
15990 DUK_WO_NORETURN(return NULL;);
15991}
15992
15993DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
15994 DUK_ASSERT_API_ENTRY(thr);
15995 DUK_UNREF(idx);
15996 DUK_ERROR_UNSUPPORTED(thr);
15997 DUK_WO_NORETURN(return;);
15998}
15999#endif /* DUK_USE_JSON_SUPPORT */
16000#line 1 "duk_api_compile.c"
16001/*
16002 * Compilation and evaluation
16003 */
16004
16005/* #include duk_internal.h -> already included */
16006
16007typedef struct duk__compile_raw_args duk__compile_raw_args;
16008struct duk__compile_raw_args {
16009 duk_size_t src_length; /* should be first on 64-bit platforms */
16010 const duk_uint8_t *src_buffer;
16011 duk_uint_t flags;
16012};
16013
16014/* Eval is just a wrapper now. */
16015DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
16016 duk_int_t rc;
16017
16018 DUK_ASSERT_API_ENTRY(thr);
16019
16020 /* Note: strictness is *not* inherited from the current Duktape/C.
16021 * This would be confusing because the current strictness state
16022 * depends on whether we're running inside a Duktape/C activation
16023 * (= strict mode) or outside of any activation (= non-strict mode).
16024 * See tests/api/test-eval-strictness.c for more discussion.
16025 */
16026
16027 /* [ ... source? filename? ] (depends on flags) */
16028
16029 rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
16030
16031 /* [ ... closure/error ] */
16032
16033 if (rc != DUK_EXEC_SUCCESS) {
16034 rc = DUK_EXEC_ERROR;
16035 goto got_rc;
16036 }
16037
16038 duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
16039
16040 if (flags & DUK_COMPILE_SAFE) {
16041 rc = duk_pcall_method(thr, 0);
16042 } else {
16043 duk_call_method(thr, 0);
16044 rc = DUK_EXEC_SUCCESS;
16045 }
16046
16047 /* [ ... result/error ] */
16048
16049 got_rc:
16050 if (flags & DUK_COMPILE_NORESULT) {
16051 duk_pop(thr);
16052 }
16053
16054 return rc;
16055}
16056
16057/* Helper which can be called both directly and with duk_safe_call(). */
16058DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
16059 duk__compile_raw_args *comp_args;
16060 duk_uint_t flags;
16061 duk_hcompfunc *h_templ;
16062
16063 DUK_CTX_ASSERT_VALID(thr);
16064 DUK_ASSERT(udata != NULL);
16065
16066 /* Note: strictness is not inherited from the current Duktape/C
16067 * context. Otherwise it would not be possible to compile
16068 * non-strict code inside a Duktape/C activation (which is
16069 * always strict now). See tests/api/test-eval-strictness.c
16070 * for discussion.
16071 */
16072
16073 /* [ ... source? filename? ] (depends on flags) */
16074
16075 comp_args = (duk__compile_raw_args *) udata;
16076 flags = comp_args->flags;
16077
16078 if (flags & DUK_COMPILE_NOFILENAME) {
16079 /* Automatic filename: 'eval' or 'input'. */
16080 duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
16081 }
16082
16083 /* [ ... source? filename ] */
16084
16085 if (!comp_args->src_buffer) {
16086 duk_hstring *h_sourcecode;
16087
16088 h_sourcecode = duk_get_hstring(thr, -2);
16089 if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
16090 (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
16091 DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
16092 DUK_WO_NORETURN(return 0;);
16093 }
16094 DUK_ASSERT(h_sourcecode != NULL);
16095 comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
16096 comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
16097 }
16098 DUK_ASSERT(comp_args->src_buffer != NULL);
16099
16100 if (flags & DUK_COMPILE_FUNCTION) {
16101 flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
16102 }
16103
16104 /* [ ... source? filename ] */
16105
16106 duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
16107
16108 /* [ ... source? func_template ] */
16109
16110 if (flags & DUK_COMPILE_NOSOURCE) {
16111 ;
16112 } else {
16113 duk_remove_m2(thr);
16114 }
16115
16116 /* [ ... func_template ] */
16117
16118 h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
16119 duk_js_push_closure(thr,
16120 h_templ,
16121 thr->builtins[DUK_BIDX_GLOBAL_ENV],
16122 thr->builtins[DUK_BIDX_GLOBAL_ENV],
16123 1 /*add_auto_proto*/);
16124 duk_remove_m2(thr); /* -> [ ... closure ] */
16125
16126 /* [ ... closure ] */
16127
16128 return 1;
16129}
16130
16131DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
16132 duk__compile_raw_args comp_args_alloc;
16133 duk__compile_raw_args *comp_args = &comp_args_alloc;
16134
16135 DUK_ASSERT_API_ENTRY(thr);
16136
16137 if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
16138 /* String length is computed here to avoid multiple evaluation
16139 * of a macro argument in the calling side.
16140 */
16141 src_length = DUK_STRLEN(src_buffer);
16142 }
16143
16144 comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
16145 comp_args->src_length = src_length;
16146 comp_args->flags = flags;
16147
16148 /* [ ... source? filename? ] (depends on flags) */
16149
16150 if (flags & DUK_COMPILE_SAFE) {
16151 duk_int_t rc;
16152 duk_int_t nargs;
16153 duk_int_t nrets = 1;
16154
16155 /* Arguments can be: [ source? filename? &comp_args] so that
16156 * nargs is 1 to 3. Call site encodes the correct nargs count
16157 * directly into flags.
16158 */
16159 nargs = flags & 0x07;
16160 DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
16161 ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
16162 rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
16163
16164 /* [ ... closure ] */
16165 return rc;
16166 }
16167
16168 (void) duk__do_compile(thr, (void *) comp_args);
16169
16170 /* [ ... closure ] */
16171 return DUK_EXEC_SUCCESS;
16172}
16173#line 1 "duk_api_debug.c"
16174/*
16175 * Debugging related API calls
16176 */
16177
16178/* #include duk_internal.h -> already included */
16179
16180#if defined(DUK_USE_JSON_SUPPORT)
16181DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
16182 duk_idx_t idx;
16183 duk_idx_t top;
16184
16185 DUK_ASSERT_API_ENTRY(thr);
16186
16187 /* We don't duk_require_stack() here now, but rely on the caller having
16188 * enough space.
16189 */
16190
16191 top = duk_get_top(thr);
16192 duk_push_bare_array(thr);
16193 for (idx = 0; idx < top; idx++) {
16194 duk_dup(thr, idx);
16195 duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
16196 }
16197
16198 /* XXX: conversion errors should not propagate outwards.
16199 * Perhaps values need to be coerced individually?
16200 */
16201 duk_bi_json_stringify_helper(thr,
16202 duk_get_top_index(thr), /*idx_value*/
16203 DUK_INVALID_INDEX, /*idx_replacer*/
16204 DUK_INVALID_INDEX, /*idx_space*/
16205 DUK_JSON_FLAG_EXT_CUSTOM |
16206 DUK_JSON_FLAG_ASCII_ONLY |
16207 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
16208
16209 duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
16210 duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
16211 duk_pop(thr);
16212 DUK_ASSERT(duk_is_string(thr, -1));
16213}
16214#else /* DUK_USE_JSON_SUPPORT */
16215DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
16216 DUK_ASSERT_API_ENTRY(thr);
16217 DUK_ERROR_UNSUPPORTED(thr);
16218 DUK_WO_NORETURN(return;);
16219}
16220#endif /* DUK_USE_JSON_SUPPORT */
16221
16222#if defined(DUK_USE_DEBUGGER_SUPPORT)
16223
16224DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
16225 duk_debug_read_function read_cb,
16226 duk_debug_write_function write_cb,
16227 duk_debug_peek_function peek_cb,
16228 duk_debug_read_flush_function read_flush_cb,
16229 duk_debug_write_flush_function write_flush_cb,
16230 duk_debug_request_function request_cb,
16231 duk_debug_detached_function detached_cb,
16232 void *udata) {
16233 duk_heap *heap;
16234 const char *str;
16235 duk_size_t len;
16236
16237 /* XXX: should there be an error or an automatic detach if
16238 * already attached?
16239 */
16240
16241 DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
16242
16243 DUK_ASSERT_API_ENTRY(thr);
16244 DUK_ASSERT(read_cb != NULL);
16245 DUK_ASSERT(write_cb != NULL);
16246 /* Other callbacks are optional. */
16247
16248 heap = thr->heap;
16249 heap->dbg_read_cb = read_cb;
16250 heap->dbg_write_cb = write_cb;
16251 heap->dbg_peek_cb = peek_cb;
16252 heap->dbg_read_flush_cb = read_flush_cb;
16253 heap->dbg_write_flush_cb = write_flush_cb;
16254 heap->dbg_request_cb = request_cb;
16255 heap->dbg_detached_cb = detached_cb;
16256 heap->dbg_udata = udata;
16257 heap->dbg_have_next_byte = 0;
16258
16259 /* Start in paused state. */
16260 heap->dbg_processing = 0;
16261 heap->dbg_state_dirty = 0;
16262 heap->dbg_force_restart = 0;
16263 heap->dbg_pause_flags = 0;
16264 heap->dbg_pause_act = NULL;
16265 heap->dbg_pause_startline = 0;
16266 heap->dbg_exec_counter = 0;
16267 heap->dbg_last_counter = 0;
16268 heap->dbg_last_time = 0.0;
16269 duk_debug_set_paused(heap); /* XXX: overlap with fields above */
16270
16271 /* Send version identification and flush right afterwards. Note that
16272 * we must write raw, unframed bytes here.
16273 */
16274 duk_push_sprintf(thr, "%ld %ld %s %s\n",
16275 (long) DUK_DEBUG_PROTOCOL_VERSION,
16276 (long) DUK_VERSION,
16277 (const char *) DUK_GIT_DESCRIBE,
16278 (const char *) DUK_USE_TARGET_INFO);
16279 str = duk_get_lstring(thr, -1, &len);
16280 DUK_ASSERT(str != NULL);
16281 duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
16282 duk_debug_write_flush(thr);
16283 duk_pop(thr);
16284}
16285
16286DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
16287 DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
16288
16289 DUK_ASSERT_API_ENTRY(thr);
16290 DUK_ASSERT(thr->heap != NULL);
16291
16292 /* Can be called multiple times with no harm. */
16293 duk_debug_do_detach(thr->heap);
16294}
16295
16296DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
16297 duk_bool_t processed_messages;
16298
16299 DUK_ASSERT_API_ENTRY(thr);
16300 DUK_ASSERT(thr->heap != NULL);
16301
16302 if (!duk_debug_is_attached(thr->heap)) {
16303 return;
16304 }
16305 if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
16306 /* Calling duk_debugger_cooperate() while Duktape is being
16307 * called into is not supported. This is not a 100% check
16308 * but prevents any damage in most cases.
16309 */
16310 return;
16311 }
16312
16313 processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
16314 DUK_UNREF(processed_messages);
16315}
16316
16317DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
16318 duk_idx_t top;
16319 duk_idx_t idx;
16320 duk_bool_t ret = 0;
16321
16322 DUK_ASSERT_API_ENTRY(thr);
16323 DUK_ASSERT(thr->heap != NULL);
16324
16325 DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
16326
16327 top = duk_get_top(thr);
16328 if (top < nvalues) {
16329 DUK_ERROR_RANGE(thr, "not enough stack values for notify");
16330 DUK_WO_NORETURN(return 0;);
16331 }
16332 if (duk_debug_is_attached(thr->heap)) {
16333 duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
16334 for (idx = top - nvalues; idx < top; idx++) {
16335 duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
16336 duk_debug_write_tval(thr, tv);
16337 }
16338 duk_debug_write_eom(thr);
16339
16340 /* Return non-zero (true) if we have a good reason to believe
16341 * the notify was delivered; if we're still attached at least
16342 * a transport error was not indicated by the transport write
16343 * callback. This is not a 100% guarantee of course.
16344 */
16345 if (duk_debug_is_attached(thr->heap)) {
16346 ret = 1;
16347 }
16348 }
16349 duk_pop_n(thr, nvalues);
16350 return ret;
16351}
16352
16353DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
16354 DUK_ASSERT_API_ENTRY(thr);
16355 DUK_ASSERT(thr->heap != NULL);
16356
16357 DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
16358
16359 /* Treat like a debugger statement: ignore when not attached. */
16360 if (duk_debug_is_attached(thr->heap)) {
16361 if (duk_debug_is_paused(thr->heap)) {
16362 DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring"));
16363 } else {
16364 duk_debug_set_paused(thr->heap);
16365
16366 /* Pause on the next opcode executed. This is always safe to do even
16367 * inside the debugger message loop: the interrupt counter will be reset
16368 * to its proper value when the message loop exits.
16369 */
16370 thr->interrupt_init = 1;
16371 thr->interrupt_counter = 0;
16372 }
16373 }
16374}
16375
16376#else /* DUK_USE_DEBUGGER_SUPPORT */
16377
16378DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
16379 duk_debug_read_function read_cb,
16380 duk_debug_write_function write_cb,
16381 duk_debug_peek_function peek_cb,
16382 duk_debug_read_flush_function read_flush_cb,
16383 duk_debug_write_flush_function write_flush_cb,
16384 duk_debug_request_function request_cb,
16385 duk_debug_detached_function detached_cb,
16386 void *udata) {
16387 DUK_ASSERT_API_ENTRY(thr);
16388 DUK_UNREF(read_cb);
16389 DUK_UNREF(write_cb);
16390 DUK_UNREF(peek_cb);
16391 DUK_UNREF(read_flush_cb);
16392 DUK_UNREF(write_flush_cb);
16393 DUK_UNREF(request_cb);
16394 DUK_UNREF(detached_cb);
16395 DUK_UNREF(udata);
16396 DUK_ERROR_TYPE(thr, "no debugger support");
16397 DUK_WO_NORETURN(return;);
16398}
16399
16400DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
16401 DUK_ASSERT_API_ENTRY(thr);
16402 DUK_ERROR_TYPE(thr, "no debugger support");
16403 DUK_WO_NORETURN(return;);
16404}
16405
16406DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
16407 /* nop */
16408 DUK_ASSERT_API_ENTRY(thr);
16409 DUK_UNREF(thr);
16410}
16411
16412DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
16413 duk_idx_t top;
16414
16415 DUK_ASSERT_API_ENTRY(thr);
16416
16417 top = duk_get_top(thr);
16418 if (top < nvalues) {
16419 DUK_ERROR_RANGE_INVALID_COUNT(thr);
16420 DUK_WO_NORETURN(return 0;);
16421 }
16422
16423 /* No debugger support, just pop values. */
16424 duk_pop_n(thr, nvalues);
16425 return 0;
16426}
16427
16428DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
16429 /* Treat like debugger statement: nop */
16430 DUK_ASSERT_API_ENTRY(thr);
16431 DUK_UNREF(thr);
16432}
16433
16434#endif /* DUK_USE_DEBUGGER_SUPPORT */
16435#line 1 "duk_api_heap.c"
16436/*
16437 * Heap creation and destruction
16438 */
16439
16440/* #include duk_internal.h -> already included */
16441
16442typedef struct duk_internal_thread_state duk_internal_thread_state;
16443
16444struct duk_internal_thread_state {
16445 duk_ljstate lj;
16446 duk_bool_t creating_error;
16447 duk_hthread *curr_thread;
16448 duk_uint8_t thread_state;
16449 duk_int_t call_recursion_depth;
16450};
16451
16452DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
16453 duk_realloc_function realloc_func,
16454 duk_free_function free_func,
16455 void *heap_udata,
16456 duk_fatal_function fatal_handler) {
16457 duk_heap *heap = NULL;
16458 duk_hthread *thr;
16459
16460 /* Assume that either all memory funcs are NULL or non-NULL, mixed
16461 * cases will now be unsafe.
16462 */
16463
16464 /* XXX: just assert non-NULL values here and make caller arguments
16465 * do the defaulting to the default implementations (smaller code)?
16466 */
16467
16468 if (!alloc_func) {
16469 DUK_ASSERT(realloc_func == NULL);
16470 DUK_ASSERT(free_func == NULL);
16471#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
16472 alloc_func = duk_default_alloc_function;
16473 realloc_func = duk_default_realloc_function;
16474 free_func = duk_default_free_function;
16475#else
16476 DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
16477 return NULL;
16478#endif
16479 } else {
16480 DUK_ASSERT(realloc_func != NULL);
16481 DUK_ASSERT(free_func != NULL);
16482 }
16483
16484 if (!fatal_handler) {
16485 fatal_handler = duk_default_fatal_handler;
16486 }
16487
16488 DUK_ASSERT(alloc_func != NULL);
16489 DUK_ASSERT(realloc_func != NULL);
16490 DUK_ASSERT(free_func != NULL);
16491 DUK_ASSERT(fatal_handler != NULL);
16492
16493 heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
16494 if (!heap) {
16495 return NULL;
16496 }
16497 thr = heap->heap_thread;
16498 DUK_ASSERT(thr != NULL);
16499 DUK_ASSERT(thr->heap != NULL);
16500 return thr;
16501}
16502
16503DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
16504 duk_heap *heap;
16505
16506 if (!thr) {
16507 return;
16508 }
16509 DUK_ASSERT_API_ENTRY(thr);
16510 heap = thr->heap;
16511 DUK_ASSERT(heap != NULL);
16512
16513 duk_heap_free(heap);
16514}
16515
16516DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
16517 duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
16518 duk_heap *heap;
16519 duk_ljstate *lj;
16520
16521 DUK_ASSERT_API_ENTRY(thr);
16522 DUK_ASSERT(thr->heap != NULL);
16523 DUK_ASSERT(state != NULL); /* unvalidated */
16524
16525 /* Currently not supported when called from within a finalizer.
16526 * If that is done, the finalizer will remain running indefinitely,
16527 * preventing other finalizers from executing. The assert is a bit
16528 * wider, checking that it would be OK to run pending finalizers.
16529 */
16530 DUK_ASSERT(thr->heap->pf_prevent_count == 0);
16531
16532 /* Currently not supported to duk_suspend() from an errCreate()
16533 * call.
16534 */
16535 DUK_ASSERT(thr->heap->creating_error == 0);
16536
16537 heap = thr->heap;
16538 lj = &heap->lj;
16539
16540 duk_push_tval(thr, &lj->value1);
16541 duk_push_tval(thr, &lj->value2);
16542
16543 /* XXX: creating_error == 0 is asserted above, so no need to store. */
16544 duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
16545 snapshot->creating_error = heap->creating_error;
16546 snapshot->curr_thread = heap->curr_thread;
16547 snapshot->thread_state = thr->state;
16548 snapshot->call_recursion_depth = heap->call_recursion_depth;
16549
16550 lj->jmpbuf_ptr = NULL;
16551 lj->type = DUK_LJ_TYPE_UNKNOWN;
16552 DUK_TVAL_SET_UNDEFINED(&lj->value1);
16553 DUK_TVAL_SET_UNDEFINED(&lj->value2);
16554 heap->creating_error = 0;
16555 heap->curr_thread = NULL;
16556 heap->call_recursion_depth = 0;
16557
16558 thr->state = DUK_HTHREAD_STATE_INACTIVE;
16559}
16560
16561DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
16562 const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
16563 duk_heap *heap;
16564
16565 DUK_ASSERT_API_ENTRY(thr);
16566 DUK_ASSERT(thr->heap != NULL);
16567 DUK_ASSERT(state != NULL); /* unvalidated */
16568
16569 /* Shouldn't be necessary if duk_suspend() is called before
16570 * duk_resume(), but assert in case API sequence is incorrect.
16571 */
16572 DUK_ASSERT(thr->heap->pf_prevent_count == 0);
16573 DUK_ASSERT(thr->heap->creating_error == 0);
16574
16575 thr->state = snapshot->thread_state;
16576
16577 heap = thr->heap;
16578
16579 duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
16580 heap->creating_error = snapshot->creating_error;
16581 heap->curr_thread = snapshot->curr_thread;
16582 heap->call_recursion_depth = snapshot->call_recursion_depth;
16583
16584 duk_pop_2(thr);
16585}
16586
16587/* XXX: better place for this */
16588DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
16589 duk_hobject *h_glob;
16590 duk_hobject *h_prev_glob;
16591 duk_hobjenv *h_env;
16592 duk_hobject *h_prev_env;
16593
16594 DUK_ASSERT_API_ENTRY(thr);
16595
16596 DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
16597
16598 h_glob = duk_require_hobject(thr, -1);
16599 DUK_ASSERT(h_glob != NULL);
16600
16601 /*
16602 * Replace global object.
16603 */
16604
16605 h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
16606 DUK_UNREF(h_prev_glob);
16607 thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
16608 DUK_HOBJECT_INCREF(thr, h_glob);
16609 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
16610
16611 /*
16612 * Replace lexical environment for global scope
16613 *
16614 * Create a new object environment for the global lexical scope.
16615 * We can't just reset the _Target property of the current one,
16616 * because the lexical scope is shared by other threads with the
16617 * same (initial) built-ins.
16618 */
16619
16620 h_env = duk_hobjenv_alloc(thr,
16621 DUK_HOBJECT_FLAG_EXTENSIBLE |
16622 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
16623 DUK_ASSERT(h_env != NULL);
16624 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL);
16625
16626 DUK_ASSERT(h_env->target == NULL);
16627 DUK_ASSERT(h_glob != NULL);
16628 h_env->target = h_glob;
16629 DUK_HOBJECT_INCREF(thr, h_glob);
16630 DUK_ASSERT(h_env->has_this == 0);
16631
16632 /* [ ... new_glob ] */
16633
16634 h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
16635 thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env;
16636 DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env);
16637 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
16638 DUK_UNREF(h_env); /* without refcounts */
16639 DUK_UNREF(h_prev_env);
16640
16641 /* [ ... new_glob ] */
16642
16643 duk_pop(thr);
16644
16645 /* [ ... ] */
16646}
16647#line 1 "duk_api_inspect.c"
16648/*
16649 * Inspection
16650 */
16651
16652/* #include duk_internal.h -> already included */
16653
16654/* For footprint efficient multiple value setting: arrays are much better than
16655 * varargs, format string with parsing is often better than string pointer arrays.
16656 */
16657DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
16658 duk_int_t val;
16659 const char *p;
16660 const char *p_curr;
16661 duk_size_t len;
16662
16663 for (p = fmt;;) {
16664 len = DUK_STRLEN(p);
16665 p_curr = p;
16666 p += len + 1;
16667 if (len == 0) {
16668 /* Double NUL (= empty key) terminates. */
16669 break;
16670 }
16671 val = *vals++;
16672 if (val >= 0) {
16673 /* Negative values are markers to skip key. */
16674 duk_push_string(thr, p_curr);
16675 duk_push_int(thr, val);
16676 duk_put_prop(thr, -3);
16677 }
16678 }
16679}
16680
16681/* Raw helper to extract internal information / statistics about a value.
16682 * The return value is an object with properties that are version specific.
16683 * The properties must not expose anything that would lead to security
16684 * issues (e.g. exposing compiled function 'data' buffer might be an issue).
16685 * Currently only counts and sizes and such are given so there shouldn't
16686 * be security implications.
16687 */
16688
16689#define DUK__IDX_TYPE 0
16690#define DUK__IDX_ITAG 1
16691#define DUK__IDX_REFC 2
16692#define DUK__IDX_HBYTES 3
16693#define DUK__IDX_CLASS 4
16694#define DUK__IDX_PBYTES 5
16695#define DUK__IDX_ESIZE 6
16696#define DUK__IDX_ENEXT 7
16697#define DUK__IDX_ASIZE 8
16698#define DUK__IDX_HSIZE 9
16699#define DUK__IDX_BCBYTES 10
16700#define DUK__IDX_DBYTES 11
16701#define DUK__IDX_TSTATE 12
16702#define DUK__IDX_VARIANT 13
16703
16704DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
16705 duk_tval *tv;
16706 duk_heaphdr *h;
16707 /* The temporary values should be in an array rather than individual
16708 * variables which (in practice) ensures that the compiler won't map
16709 * them to registers and emit a lot of unnecessary shuffling code.
16710 */
16711 duk_int_t vals[14];
16712
16713 DUK_ASSERT_API_ENTRY(thr);
16714
16715 /* Assume two's complement and set everything to -1. */
16716 duk_memset((void *) &vals, (int) 0xff, sizeof(vals));
16717 DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
16718
16719 tv = duk_get_tval_or_unused(thr, idx);
16720 h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
16721
16722 vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
16723 vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
16724
16725 duk_push_bare_object(thr); /* Invalidates 'tv'. */
16726 tv = NULL;
16727
16728 if (h == NULL) {
16729 goto finish;
16730 }
16731 duk_push_pointer(thr, (void *) h);
16732 duk_put_prop_literal(thr, -2, "hptr");
16733
16734#if 0
16735 /* Covers a lot of information, e.g. buffer and string variants. */
16736 duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
16737 duk_put_prop_literal(thr, -2, "hflags");
16738#endif
16739
16740#if defined(DUK_USE_REFERENCE_COUNTING)
16741 vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
16742#endif
16743 vals[DUK__IDX_VARIANT] = 0;
16744
16745 /* Heaphdr size and additional allocation size, followed by
16746 * type specific stuff (with varying value count).
16747 */
16748 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
16749 case DUK_HTYPE_STRING: {
16750 duk_hstring *h_str = (duk_hstring *) h;
16751 vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
16752#if defined(DUK_USE_HSTRING_EXTDATA)
16753 if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
16754 vals[DUK__IDX_VARIANT] = 1;
16755 }
16756#endif
16757 break;
16758 }
16759 case DUK_HTYPE_OBJECT: {
16760 duk_hobject *h_obj = (duk_hobject *) h;
16761
16762 /* XXX: variants here are maybe pointless; class is enough? */
16763 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
16764 vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
16765 } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
16766 vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
16767 } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
16768 vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
16769 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
16770 vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
16771 vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
16772#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
16773 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
16774 vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
16775 /* XXX: some size information */
16776#endif
16777 } else {
16778 vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
16779 }
16780
16781 vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
16782 vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj);
16783 vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
16784 vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
16785 vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
16786 vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
16787
16788 /* Note: e_next indicates the number of gc-reachable entries
16789 * in the entry part, and also indicates the index where the
16790 * next new property would be inserted. It does *not* indicate
16791 * the number of non-NULL keys present in the object. That
16792 * value could be counted separately but requires a pass through
16793 * the key list.
16794 */
16795
16796 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
16797 duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
16798 vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
16799 }
16800 break;
16801 }
16802 case DUK_HTYPE_BUFFER: {
16803 duk_hbuffer *h_buf = (duk_hbuffer *) h;
16804
16805 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
16806 if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
16807 vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */
16808 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
16809 } else {
16810 /* When alloc_size == 0 the second allocation may not
16811 * actually exist.
16812 */
16813 vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
16814 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
16815 }
16816 vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
16817 } else {
16818 DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
16819 vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
16820 }
16821 break;
16822 }
16823 }
16824
16825 finish:
16826 duk__inspect_multiple_uint(thr,
16827 "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
16828 "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
16829 "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
16830 (duk_int_t *) &vals);
16831}
16832
16833DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
16834 duk_activation *act;
16835 duk_uint_fast32_t pc;
16836 duk_uint_fast32_t line;
16837
16838 DUK_ASSERT_API_ENTRY(thr);
16839
16840 /* -1 = top callstack entry
16841 * -2 = caller of level -1
16842 * etc
16843 */
16844 act = duk_hthread_get_activation_for_level(thr, level);
16845 if (act == NULL) {
16846 duk_push_undefined(thr);
16847 return;
16848 }
16849 duk_push_bare_object(thr);
16850
16851 /* Relevant PC is just before current one because PC is
16852 * post-incremented. This should match what error augment
16853 * code does.
16854 */
16855 pc = duk_hthread_get_act_prev_pc(thr, act);
16856
16857 duk_push_tval(thr, &act->tv_func);
16858
16859 duk_push_uint(thr, (duk_uint_t) pc);
16860 duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
16861
16862#if defined(DUK_USE_PC2LINE)
16863 line = duk_hobject_pc2line_query(thr, -1, pc);
16864#else
16865 line = 0;
16866#endif
16867 duk_push_uint(thr, (duk_uint_t) line);
16868 duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
16869
16870 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
16871 /* Providing access to e.g. act->lex_env would be dangerous: these
16872 * internal structures must never be accessible to the application.
16873 * Duktape relies on them having consistent data, and this consistency
16874 * is only asserted for, not checked for.
16875 */
16876}
16877
16878/* automatic undefs */
16879#undef DUK__IDX_ASIZE
16880#undef DUK__IDX_BCBYTES
16881#undef DUK__IDX_CLASS
16882#undef DUK__IDX_DBYTES
16883#undef DUK__IDX_ENEXT
16884#undef DUK__IDX_ESIZE
16885#undef DUK__IDX_HBYTES
16886#undef DUK__IDX_HSIZE
16887#undef DUK__IDX_ITAG
16888#undef DUK__IDX_PBYTES
16889#undef DUK__IDX_REFC
16890#undef DUK__IDX_TSTATE
16891#undef DUK__IDX_TYPE
16892#undef DUK__IDX_VARIANT
16893#line 1 "duk_api_memory.c"
16894/*
16895 * Memory calls.
16896 */
16897
16898/* #include duk_internal.h -> already included */
16899
16900DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
16901 DUK_ASSERT_API_ENTRY(thr);
16902
16903 return DUK_ALLOC_RAW(thr->heap, size);
16904}
16905
16906DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
16907 DUK_ASSERT_API_ENTRY(thr);
16908
16909 DUK_FREE_RAW(thr->heap, ptr);
16910}
16911
16912DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
16913 DUK_ASSERT_API_ENTRY(thr);
16914
16915 return DUK_REALLOC_RAW(thr->heap, ptr, size);
16916}
16917
16918DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
16919 DUK_ASSERT_API_ENTRY(thr);
16920
16921 return DUK_ALLOC(thr->heap, size);
16922}
16923
16924DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
16925 DUK_ASSERT_API_ENTRY(thr);
16926
16927 DUK_FREE_CHECKED(thr, ptr);
16928}
16929
16930DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
16931 DUK_ASSERT_API_ENTRY(thr);
16932
16933 /*
16934 * Note: since this is an exposed API call, there should be
16935 * no way a mark-and-sweep could have a side effect on the
16936 * memory allocation behind 'ptr'; the pointer should never
16937 * be something that Duktape wants to change.
16938 *
16939 * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
16940 * have the storage location here anyway).
16941 */
16942
16943 return DUK_REALLOC(thr->heap, ptr, size);
16944}
16945
16946DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
16947 duk_heap *heap;
16948
16949 DUK_ASSERT_API_ENTRY(thr);
16950 DUK_ASSERT(out_funcs != NULL);
16951 DUK_ASSERT(thr != NULL);
16952 DUK_ASSERT(thr->heap != NULL);
16953
16954 heap = thr->heap;
16955 out_funcs->alloc_func = heap->alloc_func;
16956 out_funcs->realloc_func = heap->realloc_func;
16957 out_funcs->free_func = heap->free_func;
16958 out_funcs->udata = heap->heap_udata;
16959}
16960
16961DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
16962 duk_heap *heap;
16963 duk_small_uint_t ms_flags;
16964
16965 DUK_ASSERT_API_ENTRY(thr);
16966 heap = thr->heap;
16967 DUK_ASSERT(heap != NULL);
16968
16969 DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
16970 DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */
16971 ms_flags = (duk_small_uint_t) flags;
16972 duk_heap_mark_and_sweep(heap, ms_flags);
16973}
16974#line 1 "duk_api_object.c"
16975/*
16976 * Object handling: property access and other support functions.
16977 */
16978
16979/* #include duk_internal.h -> already included */
16980
16981/*
16982 * Property handling
16983 *
16984 * The API exposes only the most common property handling functions.
16985 * The caller can invoke ECMAScript built-ins for full control (e.g.
16986 * defineProperty, getOwnPropertyDescriptor).
16987 */
16988
16989DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) {
16990 duk_tval *tv_obj;
16991 duk_tval *tv_key;
16992 duk_bool_t rc;
16993
16994 DUK_ASSERT_API_ENTRY(thr);
16995
16996 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
16997 * resize is not necessary for a property get right now.
16998 */
16999
17000 tv_obj = duk_require_tval(thr, obj_idx);
17001 tv_key = duk_require_tval(thr, -1);
17002
17003 rc = duk_hobject_getprop(thr, tv_obj, tv_key);
17004 DUK_ASSERT(rc == 0 || rc == 1);
17005 /* a value is left on stack regardless of rc */
17006
17007 duk_remove_m2(thr); /* remove key */
17008 DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1);
17009 return rc; /* 1 if property found, 0 otherwise */
17010}
17011
17012DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
17013 DUK_ASSERT_API_ENTRY(thr);
17014 DUK_ASSERT(key != NULL);
17015
17016 obj_idx = duk_require_normalize_index(thr, obj_idx);
17017 (void) duk_push_string(thr, key);
17018 return duk_get_prop(thr, obj_idx);
17019}
17020
17021DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17022 DUK_ASSERT_API_ENTRY(thr);
17023 DUK_ASSERT(key != NULL);
17024
17025 obj_idx = duk_require_normalize_index(thr, obj_idx);
17026 (void) duk_push_lstring(thr, key, key_len);
17027 return duk_get_prop(thr, obj_idx);
17028}
17029
17030#if !defined(DUK_USE_PREFER_SIZE)
17031DUK_EXTERNAL duk_bool_t duk_get_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17032 DUK_ASSERT_API_ENTRY(thr);
17033 DUK_ASSERT(key != NULL);
17034 DUK_ASSERT(key[key_len] == (char) 0);
17035
17036 obj_idx = duk_require_normalize_index(thr, obj_idx);
17037 (void) duk_push_literal_raw(thr, key, key_len);
17038 return duk_get_prop(thr, obj_idx);
17039}
17040#endif
17041
17042DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
17043 DUK_ASSERT_API_ENTRY(thr);
17044
17045 obj_idx = duk_require_normalize_index(thr, obj_idx);
17046 duk_push_uarridx(thr, arr_idx);
17047 return duk_get_prop(thr, obj_idx);
17048}
17049
17050DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
17051 DUK_ASSERT_API_ENTRY(thr);
17052
17053 obj_idx = duk_require_normalize_index(thr, obj_idx);
17054 (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
17055 return duk_get_prop(thr, obj_idx);
17056}
17057
17058DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17059 DUK_ASSERT_API_ENTRY(thr);
17060 DUK_ASSERT_STRIDX_VALID(stridx);
17061
17062 obj_idx = duk_require_normalize_index(thr, obj_idx);
17063 (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
17064 return duk_get_prop(thr, obj_idx);
17065}
17066
17067DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17068 return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
17069 (duk_small_uint_t) (packed_args & 0xffffUL));
17070}
17071
17072DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
17073 duk_bool_t rc;
17074
17075 DUK_ASSERT_API_ENTRY(thr);
17076 DUK_ASSERT_STRIDX_VALID(stridx);
17077
17078 rc = duk_get_prop_stridx(thr, obj_idx, stridx);
17079 if (out_has_prop) {
17080 *out_has_prop = rc;
17081 }
17082 return duk_to_boolean_top_pop(thr);
17083}
17084
17085/* This get variant is for internal use, it differs from standard
17086 * duk_get_prop() in that:
17087 * - Object argument must be an object (primitive values not supported).
17088 * - Key argument must be a string (no coercion).
17089 * - Only own properties are checked (no inheritance). Only "entry part"
17090 * properties are checked (not array index properties).
17091 * - Property must be a plain data property, not a getter.
17092 * - Proxy traps are not triggered.
17093 */
17094DUK_INTERNAL duk_bool_t duk_xget_owndataprop(duk_hthread *thr, duk_idx_t obj_idx) {
17095 duk_hobject *h_obj;
17096 duk_hstring *h_key;
17097 duk_tval *tv_val;
17098
17099 DUK_ASSERT_API_ENTRY(thr);
17100
17101 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
17102 * resize is not necessary for a property get right now.
17103 */
17104
17105 h_obj = duk_get_hobject(thr, obj_idx);
17106 if (h_obj == NULL) {
17107 return 0;
17108 }
17109 h_key = duk_require_hstring(thr, -1);
17110
17111 tv_val = duk_hobject_find_entry_tval_ptr(thr->heap, h_obj, h_key);
17112 if (tv_val == NULL) {
17113 return 0;
17114 }
17115
17116 duk_push_tval(thr, tv_val);
17117 duk_remove_m2(thr); /* remove key */
17118
17119 return 1;
17120}
17121
17122DUK_INTERNAL duk_bool_t duk_xget_owndataprop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17123 DUK_ASSERT_API_ENTRY(thr);
17124 DUK_ASSERT_STRIDX_VALID(stridx);
17125
17126 obj_idx = duk_require_normalize_index(thr, obj_idx);
17127 (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
17128 return duk_xget_owndataprop(thr, obj_idx);
17129}
17130
17131DUK_INTERNAL duk_bool_t duk_xget_owndataprop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17132 return duk_xget_owndataprop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
17133 (duk_small_uint_t) (packed_args & 0xffffUL));
17134}
17135
17136DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
17137 duk_tval *tv_obj;
17138 duk_tval *tv_key;
17139 duk_tval *tv_val;
17140 duk_bool_t throw_flag;
17141 duk_bool_t rc;
17142
17143 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
17144 * resize is not necessary for a property put right now (putprop protects
17145 * against it internally).
17146 */
17147
17148 /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key,
17149 * idx_val is always (idx_key ^ 0x01).
17150 */
17151 DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
17152 (idx_key == -1 && (idx_key ^ 1) == -2));
17153 /* XXX: Direct access; faster validation. */
17154 tv_obj = duk_require_tval(thr, obj_idx);
17155 tv_key = duk_require_tval(thr, idx_key);
17156 tv_val = duk_require_tval(thr, idx_key ^ 1);
17157 throw_flag = duk_is_strict_call(thr);
17158
17159 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
17160 DUK_ASSERT(rc == 0 || rc == 1);
17161
17162 duk_pop_2(thr); /* remove key and value */
17163 return rc; /* 1 if property found, 0 otherwise */
17164}
17165
17166DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) {
17167 DUK_ASSERT_API_ENTRY(thr);
17168 return duk__put_prop_shared(thr, obj_idx, -2);
17169}
17170
17171DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
17172 DUK_ASSERT_API_ENTRY(thr);
17173 DUK_ASSERT(key != NULL);
17174
17175 /* Careful here and with other duk_put_prop_xxx() helpers: the
17176 * target object and the property value may be in the same value
17177 * stack slot (unusual, but still conceptually clear).
17178 */
17179 obj_idx = duk_normalize_index(thr, obj_idx);
17180 (void) duk_push_string(thr, key);
17181 return duk__put_prop_shared(thr, obj_idx, -1);
17182}
17183
17184DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17185 DUK_ASSERT_API_ENTRY(thr);
17186 DUK_ASSERT(key != NULL);
17187
17188 obj_idx = duk_normalize_index(thr, obj_idx);
17189 (void) duk_push_lstring(thr, key, key_len);
17190 return duk__put_prop_shared(thr, obj_idx, -1);
17191}
17192
17193#if !defined(DUK_USE_PREFER_SIZE)
17194DUK_EXTERNAL duk_bool_t duk_put_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17195 DUK_ASSERT_API_ENTRY(thr);
17196 DUK_ASSERT(key != NULL);
17197 DUK_ASSERT(key[key_len] == (char) 0);
17198
17199 obj_idx = duk_normalize_index(thr, obj_idx);
17200 (void) duk_push_literal_raw(thr, key, key_len);
17201 return duk__put_prop_shared(thr, obj_idx, -1);
17202}
17203#endif
17204
17205DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
17206 DUK_ASSERT_API_ENTRY(thr);
17207
17208 obj_idx = duk_require_normalize_index(thr, obj_idx);
17209 duk_push_uarridx(thr, arr_idx);
17210 return duk__put_prop_shared(thr, obj_idx, -1);
17211}
17212
17213DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
17214 DUK_ASSERT_API_ENTRY(thr);
17215
17216 obj_idx = duk_require_normalize_index(thr, obj_idx);
17217 (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
17218 return duk__put_prop_shared(thr, obj_idx, -1);
17219}
17220
17221
17222DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17223 DUK_ASSERT_API_ENTRY(thr);
17224 DUK_ASSERT_STRIDX_VALID(stridx);
17225
17226 obj_idx = duk_require_normalize_index(thr, obj_idx);
17227 duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
17228 return duk__put_prop_shared(thr, obj_idx, -1);
17229}
17230
17231DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17232 return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
17233 (duk_small_uint_t) (packed_args & 0xffffUL));
17234}
17235
17236DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) {
17237 duk_tval *tv_obj;
17238 duk_tval *tv_key;
17239 duk_bool_t throw_flag;
17240 duk_bool_t rc;
17241
17242 DUK_ASSERT_API_ENTRY(thr);
17243
17244 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
17245 * resize is not necessary for a property delete right now.
17246 */
17247
17248 tv_obj = duk_require_tval(thr, obj_idx);
17249 tv_key = duk_require_tval(thr, -1);
17250 throw_flag = duk_is_strict_call(thr);
17251
17252 rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
17253 DUK_ASSERT(rc == 0 || rc == 1);
17254
17255 duk_pop(thr); /* remove key */
17256 return rc;
17257}
17258
17259DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
17260 DUK_ASSERT_API_ENTRY(thr);
17261 DUK_ASSERT(key != NULL);
17262
17263 obj_idx = duk_require_normalize_index(thr, obj_idx);
17264 (void) duk_push_string(thr, key);
17265 return duk_del_prop(thr, obj_idx);
17266}
17267
17268DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17269 DUK_ASSERT_API_ENTRY(thr);
17270 DUK_ASSERT(key != NULL);
17271
17272 obj_idx = duk_require_normalize_index(thr, obj_idx);
17273 (void) duk_push_lstring(thr, key, key_len);
17274 return duk_del_prop(thr, obj_idx);
17275}
17276
17277#if !defined(DUK_USE_PREFER_SIZE)
17278DUK_EXTERNAL duk_bool_t duk_del_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17279 DUK_ASSERT_API_ENTRY(thr);
17280 DUK_ASSERT(key != NULL);
17281 DUK_ASSERT(key[key_len] == (char) 0);
17282
17283 obj_idx = duk_require_normalize_index(thr, obj_idx);
17284 (void) duk_push_literal_raw(thr, key, key_len);
17285 return duk_del_prop(thr, obj_idx);
17286}
17287#endif
17288
17289DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
17290 DUK_ASSERT_API_ENTRY(thr);
17291
17292 obj_idx = duk_require_normalize_index(thr, obj_idx);
17293 duk_push_uarridx(thr, arr_idx);
17294 return duk_del_prop(thr, obj_idx);
17295}
17296
17297DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
17298 DUK_ASSERT_API_ENTRY(thr);
17299
17300 obj_idx = duk_require_normalize_index(thr, obj_idx);
17301 (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
17302 return duk_del_prop(thr, obj_idx);
17303}
17304
17305DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17306 DUK_ASSERT_API_ENTRY(thr);
17307 DUK_ASSERT_STRIDX_VALID(stridx);
17308
17309 obj_idx = duk_require_normalize_index(thr, obj_idx);
17310 duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
17311 return duk_del_prop(thr, obj_idx);
17312}
17313
17314#if 0
17315DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17316 return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
17317 (duk_small_uint_t) (packed_args & 0xffffUL));
17318}
17319#endif
17320
17321DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) {
17322 duk_tval *tv_obj;
17323 duk_tval *tv_key;
17324 duk_bool_t rc;
17325
17326 DUK_ASSERT_API_ENTRY(thr);
17327
17328 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
17329 * resize is not necessary for a property existence check right now.
17330 */
17331
17332 tv_obj = duk_require_tval(thr, obj_idx);
17333 tv_key = duk_require_tval(thr, -1);
17334
17335 rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
17336 DUK_ASSERT(rc == 0 || rc == 1);
17337
17338 duk_pop(thr); /* remove key */
17339 return rc; /* 1 if property found, 0 otherwise */
17340}
17341
17342DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
17343 DUK_ASSERT_API_ENTRY(thr);
17344 DUK_ASSERT(key != NULL);
17345
17346 obj_idx = duk_require_normalize_index(thr, obj_idx);
17347 (void) duk_push_string(thr, key);
17348 return duk_has_prop(thr, obj_idx);
17349}
17350
17351DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17352 DUK_ASSERT_API_ENTRY(thr);
17353 DUK_ASSERT(key != NULL);
17354
17355 obj_idx = duk_require_normalize_index(thr, obj_idx);
17356 (void) duk_push_lstring(thr, key, key_len);
17357 return duk_has_prop(thr, obj_idx);
17358}
17359
17360#if !defined(DUK_USE_PREFER_SIZE)
17361DUK_EXTERNAL duk_bool_t duk_has_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
17362 DUK_ASSERT_API_ENTRY(thr);
17363 DUK_ASSERT(key != NULL);
17364 DUK_ASSERT(key[key_len] == (char) 0);
17365
17366 obj_idx = duk_require_normalize_index(thr, obj_idx);
17367 (void) duk_push_literal_raw(thr, key, key_len);
17368 return duk_has_prop(thr, obj_idx);
17369}
17370#endif
17371
17372DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
17373 DUK_ASSERT_API_ENTRY(thr);
17374
17375 obj_idx = duk_require_normalize_index(thr, obj_idx);
17376 duk_push_uarridx(thr, arr_idx);
17377 return duk_has_prop(thr, obj_idx);
17378}
17379
17380DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
17381 DUK_ASSERT_API_ENTRY(thr);
17382
17383 obj_idx = duk_require_normalize_index(thr, obj_idx);
17384 (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
17385 return duk_has_prop(thr, obj_idx);
17386}
17387
17388DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17389 DUK_ASSERT_API_ENTRY(thr);
17390 DUK_ASSERT_STRIDX_VALID(stridx);
17391
17392 obj_idx = duk_require_normalize_index(thr, obj_idx);
17393 duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
17394 return duk_has_prop(thr, obj_idx);
17395}
17396
17397#if 0
17398DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17399 return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
17400 (duk_small_uint_t) (packed_args & 0xffffUL));
17401}
17402#endif
17403
17404/* Define own property without inheritance lookups and such. This differs from
17405 * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
17406 * not invoked by this method. The caller must be careful to invoke any such
17407 * behaviors if necessary.
17408 */
17409DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
17410 duk_hobject *obj;
17411 duk_hstring *key;
17412
17413 DUK_ASSERT_API_ENTRY(thr);
17414
17415 obj = duk_require_hobject(thr, obj_idx);
17416 DUK_ASSERT(obj != NULL);
17417 key = duk_to_property_key_hstring(thr, -2);
17418 DUK_ASSERT(key != NULL);
17419 DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
17420
17421 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
17422
17423 duk_pop(thr); /* pop key */
17424}
17425
17426DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
17427 duk_hobject *obj;
17428
17429 DUK_ASSERT_API_ENTRY(thr);
17430
17431 obj = duk_require_hobject(thr, obj_idx);
17432 DUK_ASSERT(obj != NULL);
17433
17434 duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
17435 /* value popped by call */
17436}
17437
17438DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
17439 duk_hobject *obj;
17440 duk_hstring *key;
17441
17442 DUK_ASSERT_API_ENTRY(thr);
17443 DUK_ASSERT_STRIDX_VALID(stridx);
17444
17445 obj = duk_require_hobject(thr, obj_idx);
17446 DUK_ASSERT(obj != NULL);
17447 key = DUK_HTHREAD_GET_STRING(thr, stridx);
17448 DUK_ASSERT(key != NULL);
17449 DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
17450
17451 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
17452 /* value popped by call */
17453}
17454
17455DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17456 duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
17457 (duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
17458 (duk_small_uint_t) (packed_args & 0xffL));
17459}
17460
17461#if 0 /*unused*/
17462DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
17463 duk_hobject *obj;
17464 duk_hstring *key;
17465
17466 DUK_ASSERT_API_ENTRY(thr);
17467 DUK_ASSERT_STRIDX_VALID(stridx);
17468 DUK_ASSERT_BIDX_VALID(builtin_idx);
17469
17470 obj = duk_require_hobject(thr, obj_idx);
17471 DUK_ASSERT(obj != NULL);
17472 key = DUK_HTHREAD_GET_STRING(thr, stridx);
17473 DUK_ASSERT(key != NULL);
17474
17475 duk_push_hobject(thr, thr->builtins[builtin_idx]);
17476 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
17477 /* value popped by call */
17478}
17479#endif
17480
17481/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
17482 * setter/getter into an object property. This is needed by the 'arguments'
17483 * object creation code, function instance creation code, and Function.prototype.bind().
17484 */
17485
17486DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17487 DUK_ASSERT_API_ENTRY(thr);
17488
17489 obj_idx = duk_require_normalize_index(thr, obj_idx);
17490 duk_push_hstring_stridx(thr, stridx);
17491 duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER);
17492 duk_dup_top(thr);
17493 duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
17494}
17495
17496/* Object.getOwnPropertyDescriptor() equivalent C binding. */
17497DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
17498 DUK_ASSERT_API_ENTRY(thr);
17499 DUK_UNREF(flags); /* no flags defined yet */
17500
17501 duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */
17502}
17503
17504/* Object.defineProperty() equivalent C binding. */
17505DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
17506 duk_idx_t idx_base;
17507 duk_hobject *obj;
17508 duk_hstring *key;
17509 duk_idx_t idx_value;
17510 duk_hobject *get;
17511 duk_hobject *set;
17512 duk_uint_t is_data_desc;
17513 duk_uint_t is_acc_desc;
17514
17515 DUK_ASSERT_API_ENTRY(thr);
17516
17517 obj = duk_require_hobject(thr, obj_idx);
17518
17519 is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
17520 is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
17521 if (is_data_desc && is_acc_desc) {
17522 /* "Have" flags must not be conflicting so that they would
17523 * apply to both a plain property and an accessor at the same
17524 * time.
17525 */
17526 goto fail_invalid_desc;
17527 }
17528
17529 idx_base = duk_get_top_index(thr);
17530 if (flags & DUK_DEFPROP_HAVE_SETTER) {
17531 duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
17532 DUK_TYPE_MASK_OBJECT |
17533 DUK_TYPE_MASK_LIGHTFUNC);
17534 set = duk_get_hobject_promote_lfunc(thr, idx_base);
17535 if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
17536 goto fail_not_callable;
17537 }
17538 idx_base--;
17539 } else {
17540 set = NULL;
17541 }
17542 if (flags & DUK_DEFPROP_HAVE_GETTER) {
17543 duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
17544 DUK_TYPE_MASK_OBJECT |
17545 DUK_TYPE_MASK_LIGHTFUNC);
17546 get = duk_get_hobject_promote_lfunc(thr, idx_base);
17547 if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
17548 goto fail_not_callable;
17549 }
17550 idx_base--;
17551 } else {
17552 get = NULL;
17553 }
17554 if (flags & DUK_DEFPROP_HAVE_VALUE) {
17555 idx_value = idx_base;
17556 idx_base--;
17557 } else {
17558 idx_value = (duk_idx_t) -1;
17559 }
17560 key = duk_to_property_key_hstring(thr, idx_base);
17561 DUK_ASSERT(key != NULL);
17562
17563 duk_require_valid_index(thr, idx_base);
17564
17565 duk_hobject_define_property_helper(thr,
17566 flags /*defprop_flags*/,
17567 obj,
17568 key,
17569 idx_value,
17570 get,
17571 set,
17572 1 /*throw_flag*/);
17573
17574 /* Clean up stack */
17575
17576 duk_set_top(thr, idx_base);
17577
17578 /* [ ... obj ... ] */
17579
17580 return;
17581
17582 fail_invalid_desc:
17583 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
17584 DUK_WO_NORETURN(return;);
17585
17586 fail_not_callable:
17587 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
17588 DUK_WO_NORETURN(return;);
17589}
17590
17591/*
17592 * Object related
17593 */
17594
17595DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) {
17596 duk_hobject *obj;
17597
17598 DUK_ASSERT_API_ENTRY(thr);
17599
17600 obj = duk_get_hobject(thr, obj_idx);
17601 if (obj) {
17602 /* Note: this may fail, caller should protect the call if necessary */
17603 duk_hobject_compact_props(thr, obj);
17604 }
17605}
17606
17607DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) {
17608 DUK_ASSERT_API_ENTRY(thr);
17609
17610 duk_compact(thr, -1);
17611}
17612
17613/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
17614
17615DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) {
17616 DUK_ASSERT_API_ENTRY(thr);
17617
17618 duk_dup(thr, obj_idx);
17619 duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
17620 duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */
17621}
17622
17623DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) {
17624 DUK_ASSERT_API_ENTRY(thr);
17625
17626 duk_require_hobject(thr, enum_index);
17627 duk_dup(thr, enum_index);
17628 return duk_hobject_enumerator_next(thr, get_value);
17629}
17630
17631DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) {
17632 duk_tval *tv;
17633 duk_hobject *h;
17634
17635 DUK_ASSERT_API_ENTRY(thr);
17636
17637 tv = duk_require_tval(thr, obj_idx);
17638 DUK_ASSERT(tv != NULL);
17639
17640 /* Seal/freeze are quite rare in practice so it'd be nice to get the
17641 * correct behavior simply via automatic promotion (at the cost of some
17642 * memory churn). However, the promoted objects don't behave the same,
17643 * e.g. promoted lightfuncs are extensible.
17644 */
17645
17646 switch (DUK_TVAL_GET_TAG(tv)) {
17647 case DUK_TAG_BUFFER:
17648 /* Plain buffer: already sealed, but not frozen (and can't be frozen
17649 * because index properties can't be made non-writable.
17650 */
17651 if (is_freeze) {
17652 goto fail_cannot_freeze;
17653 }
17654 break;
17655 case DUK_TAG_LIGHTFUNC:
17656 /* Lightfunc: already sealed and frozen, success. */
17657 break;
17658 case DUK_TAG_OBJECT:
17659 h = DUK_TVAL_GET_OBJECT(tv);
17660 DUK_ASSERT(h != NULL);
17661 if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
17662 /* Buffer objects cannot be frozen because there's no internal
17663 * support for making virtual array indices non-writable.
17664 */
17665 DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
17666 goto fail_cannot_freeze;
17667 }
17668 duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
17669
17670 /* Sealed and frozen objects cannot gain any more properties,
17671 * so this is a good time to compact them.
17672 */
17673 duk_hobject_compact_props(thr, h);
17674 break;
17675 default:
17676 /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
17677 break;
17678 }
17679 return;
17680
17681 fail_cannot_freeze:
17682 DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
17683 DUK_WO_NORETURN(return;);
17684}
17685
17686DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
17687 DUK_ASSERT_API_ENTRY(thr);
17688
17689 duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/);
17690}
17691
17692DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) {
17693 DUK_ASSERT_API_ENTRY(thr);
17694
17695 duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/);
17696}
17697
17698/*
17699 * Helpers for writing multiple properties
17700 */
17701
17702DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
17703 const duk_function_list_entry *ent = funcs;
17704
17705 DUK_ASSERT_API_ENTRY(thr);
17706
17707 obj_idx = duk_require_normalize_index(thr, obj_idx);
17708 if (ent != NULL) {
17709 while (ent->key != NULL) {
17710 duk_push_c_function(thr, ent->value, ent->nargs);
17711 duk_put_prop_string(thr, obj_idx, ent->key);
17712 ent++;
17713 }
17714 }
17715}
17716
17717DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
17718 const duk_number_list_entry *ent = numbers;
17719 duk_tval *tv;
17720
17721 DUK_ASSERT_API_ENTRY(thr);
17722
17723 obj_idx = duk_require_normalize_index(thr, obj_idx);
17724 if (ent != NULL) {
17725 while (ent->key != NULL) {
17726 tv = thr->valstack_top++;
17727 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */
17728 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */
17729 duk_put_prop_string(thr, obj_idx, ent->key);
17730 ent++;
17731 }
17732 }
17733}
17734
17735/*
17736 * Shortcut for accessing global object properties
17737 */
17738
17739DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) {
17740 duk_bool_t ret;
17741
17742 DUK_ASSERT_API_ENTRY(thr);
17743 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17744
17745 /* XXX: direct implementation */
17746
17747 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17748 ret = duk_get_prop_string(thr, -1, key);
17749 duk_remove_m2(thr);
17750 return ret;
17751}
17752
17753DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
17754 duk_bool_t ret;
17755
17756 DUK_ASSERT_API_ENTRY(thr);
17757 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17758
17759 /* XXX: direct implementation */
17760
17761 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17762 ret = duk_get_prop_lstring(thr, -1, key, key_len);
17763 duk_remove_m2(thr);
17764 return ret;
17765}
17766
17767#if !defined(DUK_USE_PREFER_SIZE)
17768DUK_EXTERNAL duk_bool_t duk_get_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
17769 duk_bool_t ret;
17770
17771 DUK_ASSERT_API_ENTRY(thr);
17772 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17773 DUK_ASSERT(key[key_len] == (char) 0);
17774
17775 /* XXX: direct implementation */
17776
17777 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17778 ret = duk_get_prop_literal_raw(thr, -1, key, key_len);
17779 duk_remove_m2(thr);
17780 return ret;
17781}
17782#endif
17783
17784DUK_EXTERNAL duk_bool_t duk_get_global_heapptr(duk_hthread *thr, void *ptr) {
17785 duk_bool_t ret;
17786
17787 DUK_ASSERT_API_ENTRY(thr);
17788 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17789
17790 /* XXX: direct implementation */
17791
17792 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17793 ret = duk_get_prop_heapptr(thr, -1, ptr);
17794 duk_remove_m2(thr);
17795 return ret;
17796}
17797
17798
17799DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
17800 duk_bool_t ret;
17801
17802 DUK_ASSERT_API_ENTRY(thr);
17803 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17804
17805 /* XXX: direct implementation */
17806
17807 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17808 duk_insert(thr, -2);
17809 ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */
17810 duk_pop(thr);
17811 return ret;
17812}
17813
17814DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
17815 duk_bool_t ret;
17816
17817 DUK_ASSERT_API_ENTRY(thr);
17818 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17819
17820 /* XXX: direct implementation */
17821
17822 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17823 duk_insert(thr, -2);
17824 ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
17825 duk_pop(thr);
17826 return ret;
17827}
17828
17829#if !defined(DUK_USE_PREFER_SIZE)
17830DUK_EXTERNAL duk_bool_t duk_put_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
17831 duk_bool_t ret;
17832
17833 DUK_ASSERT_API_ENTRY(thr);
17834 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17835 DUK_ASSERT(key[key_len] == (char) 0);
17836
17837 /* XXX: direct implementation */
17838
17839 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17840 duk_insert(thr, -2);
17841 ret = duk_put_prop_literal_raw(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
17842 duk_pop(thr);
17843 return ret;
17844}
17845#endif
17846
17847DUK_EXTERNAL duk_bool_t duk_put_global_heapptr(duk_hthread *thr, void *ptr) {
17848 duk_bool_t ret;
17849
17850 DUK_ASSERT_API_ENTRY(thr);
17851 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17852
17853 /* XXX: direct implementation */
17854
17855 duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17856 duk_insert(thr, -2);
17857 ret = duk_put_prop_heapptr(thr, -2, ptr); /* [ ... global val ] -> [ ... global ] */
17858 duk_pop(thr);
17859 return ret;
17860}
17861
17862/*
17863 * ES2015 GetMethod()
17864 */
17865
17866DUK_INTERNAL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx) {
17867 (void) duk_get_prop_stridx(thr, idx, stridx);
17868 if (duk_is_null_or_undefined(thr, -1)) {
17869 duk_pop_nodecref_unsafe(thr);
17870 return 0;
17871 }
17872 if (!duk_is_callable(thr, -1)) {
17873 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
17874 DUK_WO_NORETURN(return 0;);
17875 }
17876 return 1;
17877}
17878
17879/*
17880 * Object prototype
17881 */
17882
17883DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) {
17884 duk_hobject *obj;
17885 duk_hobject *proto;
17886
17887 DUK_ASSERT_API_ENTRY(thr);
17888
17889 obj = duk_require_hobject(thr, idx);
17890 DUK_ASSERT(obj != NULL);
17891
17892 /* XXX: shared helper for duk_push_hobject_or_undefined()? */
17893 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
17894 if (proto) {
17895 duk_push_hobject(thr, proto);
17896 } else {
17897 duk_push_undefined(thr);
17898 }
17899}
17900
17901DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
17902 duk_hobject *obj;
17903 duk_hobject *proto;
17904
17905 DUK_ASSERT_API_ENTRY(thr);
17906
17907 obj = duk_require_hobject(thr, idx);
17908 DUK_ASSERT(obj != NULL);
17909 duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED |
17910 DUK_TYPE_MASK_OBJECT);
17911 proto = duk_get_hobject(thr, -1);
17912 /* proto can also be NULL here (allowed explicitly) */
17913
17914#if defined(DUK_USE_ROM_OBJECTS)
17915 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
17916 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
17917 DUK_WO_NORETURN(return;);
17918 }
17919#endif
17920
17921 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
17922
17923 duk_pop(thr);
17924}
17925
17926DUK_INTERNAL void duk_clear_prototype(duk_hthread *thr, duk_idx_t idx) {
17927 duk_hobject *obj;
17928
17929 DUK_ASSERT_API_ENTRY(thr);
17930
17931 obj = duk_require_hobject(thr, idx);
17932 DUK_ASSERT(obj != NULL);
17933
17934#if defined(DUK_USE_ROM_OBJECTS)
17935 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
17936 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
17937 DUK_WO_NORETURN(return;);
17938 }
17939#endif
17940
17941 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, NULL);
17942}
17943
17944DUK_INTERNAL duk_bool_t duk_is_bare_object(duk_hthread *thr, duk_idx_t idx) {
17945 duk_hobject *obj;
17946 duk_hobject *proto;
17947
17948 DUK_ASSERT_API_ENTRY(thr);
17949
17950 obj = duk_require_hobject(thr, idx);
17951 DUK_ASSERT(obj != NULL);
17952
17953 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
17954 return (proto == NULL);
17955}
17956
17957/*
17958 * Object finalizer
17959 */
17960
17961#if defined(DUK_USE_FINALIZER_SUPPORT)
17962/* XXX: these could be implemented as macros calling an internal function
17963 * directly.
17964 * XXX: same issue as with Duktape.fin: there's no way to delete the property
17965 * now (just set it to undefined).
17966 */
17967DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
17968 DUK_ASSERT_API_ENTRY(thr);
17969
17970 /* This get intentionally walks the inheritance chain at present,
17971 * which matches how the effective finalizer property is also
17972 * looked up in GC.
17973 */
17974 duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
17975}
17976
17977DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
17978 duk_hobject *h;
17979 duk_bool_t callable;
17980
17981 DUK_ASSERT_API_ENTRY(thr);
17982
17983 h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */
17984 callable = duk_is_callable(thr, -1);
17985
17986 /* At present finalizer is stored as a hidden Symbol, with normal
17987 * inheritance and access control. As a result, finalizer cannot
17988 * currently be set on a non-extensible (sealed or frozen) object.
17989 * It might be useful to allow it.
17990 */
17991 duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
17992
17993 /* In addition to setting the finalizer property, keep a "have
17994 * finalizer" flag in duk_hobject in sync so that refzero can do
17995 * a very quick finalizer check by walking the prototype chain
17996 * and checking the flag alone. (Note that this means that just
17997 * setting _Finalizer on an object won't affect finalizer checks.)
17998 *
17999 * NOTE: if the argument is a Proxy object, this flag will be set
18000 * on the Proxy, not the target. As a result, the target won't get
18001 * a finalizer flag and the Proxy also won't be finalized as there's
18002 * an explicit Proxy check in finalization now.
18003 */
18004 if (callable) {
18005 DUK_HOBJECT_SET_HAVE_FINALIZER(h);
18006 } else {
18007 DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h);
18008 }
18009}
18010#else /* DUK_USE_FINALIZER_SUPPORT */
18011DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
18012 DUK_ASSERT_API_ENTRY(thr);
18013 DUK_UNREF(idx);
18014 DUK_ERROR_UNSUPPORTED(thr);
18015 DUK_WO_NORETURN(return;);
18016}
18017
18018DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
18019 DUK_ASSERT_API_ENTRY(thr);
18020 DUK_UNREF(idx);
18021 DUK_ERROR_UNSUPPORTED(thr);
18022 DUK_WO_NORETURN(return;);
18023}
18024#endif /* DUK_USE_FINALIZER_SUPPORT */
18025#line 1 "duk_api_random.c"
18026/*
18027 * Random numbers
18028 */
18029
18030/* #include duk_internal.h -> already included */
18031
18032DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) {
18033 return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr);
18034}
18035#line 1 "duk_api_stack.c"
18036/*
18037 * API calls related to general value stack manipulation: resizing the value
18038 * stack, pushing and popping values, type checking and reading values,
18039 * coercing values, etc.
18040 *
18041 * Also contains internal functions (such as duk_get_tval()), defined
18042 * in duk_api_internal.h, with semantics similar to the public API.
18043 */
18044
18045/* XXX: repetition of stack pre-checks -> helper or macro or inline */
18046/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
18047
18048/* #include duk_internal.h -> already included */
18049
18050/*
18051 * Forward declarations
18052 */
18053
18054DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx);
18055
18056/*
18057 * Global state for working around missing variadic macros
18058 */
18059
18060#if !defined(DUK_USE_VARIADIC_MACROS)
18061DUK_EXTERNAL const char *duk_api_global_filename = NULL;
18062DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
18063#endif
18064
18065/*
18066 * Misc helpers
18067 */
18068
18069DUK_LOCAL const char * const duk__symbol_type_strings[4] = {
18070 "hidden", "global", "local", "wellknown"
18071};
18072
18073#if !defined(DUK_USE_PACKED_TVAL)
18074DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
18075 DUK_TYPE_NUMBER,
18076 DUK_TYPE_NUMBER, /* fastint */
18077 DUK_TYPE_UNDEFINED,
18078 DUK_TYPE_NULL,
18079 DUK_TYPE_BOOLEAN,
18080 DUK_TYPE_POINTER,
18081 DUK_TYPE_LIGHTFUNC,
18082 DUK_TYPE_NONE,
18083 DUK_TYPE_STRING,
18084 DUK_TYPE_OBJECT,
18085 DUK_TYPE_BUFFER,
18086};
18087DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
18088 DUK_TYPE_MASK_NUMBER,
18089 DUK_TYPE_MASK_NUMBER, /* fastint */
18090 DUK_TYPE_MASK_UNDEFINED,
18091 DUK_TYPE_MASK_NULL,
18092 DUK_TYPE_MASK_BOOLEAN,
18093 DUK_TYPE_MASK_POINTER,
18094 DUK_TYPE_MASK_LIGHTFUNC,
18095 DUK_TYPE_MASK_NONE,
18096 DUK_TYPE_MASK_STRING,
18097 DUK_TYPE_MASK_OBJECT,
18098 DUK_TYPE_MASK_BUFFER,
18099};
18100#endif /* !DUK_USE_PACKED_TVAL */
18101
18102/* Assert that there's room for one value. */
18103#define DUK__ASSERT_SPACE() do { \
18104 DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
18105 } while (0)
18106
18107/* Check that there's room to push one value. */
18108#if defined(DUK_USE_VALSTACK_UNSAFE)
18109/* Faster but value stack overruns are memory unsafe. */
18110#define DUK__CHECK_SPACE() DUK__ASSERT_SPACE()
18111#else
18112#define DUK__CHECK_SPACE() do { \
18113 if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
18114 DUK_ERROR_RANGE_PUSH_BEYOND(thr); \
18115 } \
18116 } while (0)
18117#endif
18118
18119DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) {
18120 const duk_uint8_t *data;
18121 duk_size_t len;
18122
18123 DUK_ASSERT(h != NULL);
18124 DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h));
18125 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */
18126
18127 data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
18128 len = DUK_HSTRING_GET_BYTELEN(h);
18129 DUK_ASSERT(len >= 1);
18130
18131 /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */
18132
18133 if (data[0] == 0xffU) {
18134 return DUK_SYMBOL_TYPE_HIDDEN;
18135 } else if (data[0] == 0x82U) {
18136 return DUK_SYMBOL_TYPE_HIDDEN;
18137 } else if (data[0] == 0x80U) {
18138 return DUK_SYMBOL_TYPE_GLOBAL;
18139 } else if (data[len - 1] != 0xffU) {
18140 return DUK_SYMBOL_TYPE_LOCAL;
18141 } else {
18142 return DUK_SYMBOL_TYPE_WELLKNOWN;
18143 }
18144}
18145
18146DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) {
18147 duk_small_uint_t idx;
18148 idx = duk__get_symbol_type(h);
18149 DUK_ASSERT(idx < sizeof(duk__symbol_type_strings));
18150 return duk__symbol_type_strings[idx];
18151}
18152
18153DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag);
18154
18155DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
18156 duk_tval *tv;
18157 duk_small_int_t c;
18158 duk_double_t d;
18159
18160 tv = duk_get_tval_or_unused(thr, idx);
18161 DUK_ASSERT(tv != NULL);
18162
18163 /*
18164 * Special cases like NaN and +/- Infinity are handled explicitly
18165 * because a plain C coercion from double to int handles these cases
18166 * in undesirable ways. For instance, NaN may coerce to INT_MIN
18167 * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
18168 *
18169 * This double-to-int coercion differs from ToInteger() because it
18170 * has a finite range (ToInteger() allows e.g. +/- Infinity). It
18171 * also differs from ToInt32() because the INT_MIN/INT_MAX clamping
18172 * depends on the size of the int type on the platform. In particular,
18173 * on platforms with a 64-bit int type, the full range is allowed.
18174 */
18175
18176#if defined(DUK_USE_FASTINT)
18177 if (DUK_TVAL_IS_FASTINT(tv)) {
18178 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
18179#if (DUK_INT_MAX <= 0x7fffffffL)
18180 /* Clamping only necessary for 32-bit ints. */
18181 if (t < DUK_INT_MIN) {
18182 t = DUK_INT_MIN;
18183 } else if (t > DUK_INT_MAX) {
18184 t = DUK_INT_MAX;
18185 }
18186#endif
18187 return (duk_int_t) t;
18188 }
18189#endif
18190
18191 if (DUK_TVAL_IS_NUMBER(tv)) {
18192 d = DUK_TVAL_GET_NUMBER(tv);
18193 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
18194 if (c == DUK_FP_NAN) {
18195 return 0;
18196 } else if (d < (duk_double_t) DUK_INT_MIN) {
18197 /* covers -Infinity */
18198 return DUK_INT_MIN;
18199 } else if (d > (duk_double_t) DUK_INT_MAX) {
18200 /* covers +Infinity */
18201 return DUK_INT_MAX;
18202 } else {
18203 /* coerce towards zero */
18204 return (duk_int_t) d;
18205 }
18206 }
18207
18208 if (require) {
18209 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
18210 DUK_WO_NORETURN(return 0;);
18211 }
18212
18213 return def_value;
18214}
18215
18216DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
18217 duk_tval *tv;
18218 duk_small_int_t c;
18219 duk_double_t d;
18220
18221 /* Same as above but for unsigned int range. */
18222
18223 tv = duk_get_tval_or_unused(thr, idx);
18224 DUK_ASSERT(tv != NULL);
18225
18226#if defined(DUK_USE_FASTINT)
18227 if (DUK_TVAL_IS_FASTINT(tv)) {
18228 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
18229 if (t < 0) {
18230 t = 0;
18231 }
18232#if (DUK_UINT_MAX <= 0xffffffffUL)
18233 /* Clamping only necessary for 32-bit ints. */
18234 else if (t > DUK_UINT_MAX) {
18235 t = DUK_UINT_MAX;
18236 }
18237#endif
18238 return (duk_uint_t) t;
18239 }
18240#endif
18241
18242 if (DUK_TVAL_IS_NUMBER(tv)) {
18243 d = DUK_TVAL_GET_NUMBER(tv);
18244 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
18245 if (c == DUK_FP_NAN) {
18246 return 0;
18247 } else if (d < 0.0) {
18248 /* covers -Infinity */
18249 return (duk_uint_t) 0;
18250 } else if (d > (duk_double_t) DUK_UINT_MAX) {
18251 /* covers +Infinity */
18252 return (duk_uint_t) DUK_UINT_MAX;
18253 } else {
18254 /* coerce towards zero */
18255 return (duk_uint_t) d;
18256 }
18257 }
18258
18259 if (require) {
18260 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
18261 DUK_WO_NORETURN(return 0;);
18262 }
18263
18264 return def_value;
18265}
18266
18267/*
18268 * Stack index validation/normalization and getting a stack duk_tval ptr.
18269 *
18270 * These are called by many API entrypoints so the implementations must be
18271 * fast and "inlined".
18272 *
18273 * There's some repetition because of this; keep the functions in sync.
18274 */
18275
18276DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) {
18277 duk_uidx_t vs_size;
18278 duk_uidx_t uidx;
18279
18280 DUK_ASSERT_API_ENTRY(thr);
18281 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18282
18283 /* Care must be taken to avoid pointer wrapping in the index
18284 * validation. For instance, on a 32-bit platform with 8-byte
18285 * duk_tval the index 0x20000000UL would wrap the memory space
18286 * once.
18287 */
18288
18289 /* Assume value stack sizes (in elements) fits into duk_idx_t. */
18290 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18291 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18292 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
18293
18294 if (idx < 0) {
18295 uidx = vs_size + (duk_uidx_t) idx;
18296 } else {
18297 /* since index non-negative */
18298 DUK_ASSERT(idx != DUK_INVALID_INDEX);
18299 uidx = (duk_uidx_t) idx;
18300 }
18301
18302 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18303 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18304
18305 if (DUK_LIKELY(uidx < vs_size)) {
18306 return (duk_idx_t) uidx;
18307 }
18308 return DUK_INVALID_INDEX;
18309}
18310
18311DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) {
18312 duk_uidx_t vs_size;
18313 duk_uidx_t uidx;
18314
18315 DUK_ASSERT_API_ENTRY(thr);
18316 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18317
18318 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18319 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18320 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
18321
18322 if (idx < 0) {
18323 uidx = vs_size + (duk_uidx_t) idx;
18324 } else {
18325 DUK_ASSERT(idx != DUK_INVALID_INDEX);
18326 uidx = (duk_uidx_t) idx;
18327 }
18328
18329 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18330 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18331
18332 if (DUK_LIKELY(uidx < vs_size)) {
18333 return (duk_idx_t) uidx;
18334 }
18335 DUK_ERROR_RANGE_INDEX(thr, idx);
18336 DUK_WO_NORETURN(return 0;);
18337}
18338
18339DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
18340 duk_uidx_t vs_size;
18341 duk_uidx_t uidx;
18342
18343 DUK_ASSERT_API_ENTRY(thr);
18344 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18345
18346 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18347 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18348 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
18349
18350 if (idx < 0) {
18351 uidx = vs_size + (duk_uidx_t) idx;
18352 } else {
18353 DUK_ASSERT(idx != DUK_INVALID_INDEX);
18354 uidx = (duk_uidx_t) idx;
18355 }
18356
18357 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18358 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18359
18360 if (DUK_LIKELY(uidx < vs_size)) {
18361 return thr->valstack_bottom + uidx;
18362 }
18363 return NULL;
18364}
18365
18366/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval
18367 * pointer. When duk_get_tval() would return NULL, this variant returns a
18368 * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site
18369 * to avoid an unnecessary NULL check which sometimes leads to better code.
18370 * The return duk_tval is read only (at least for the UNUSED value).
18371 */
18372DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
18373
18374DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) {
18375 duk_tval *tv;
18376
18377 DUK_ASSERT_API_ENTRY(thr);
18378
18379 tv = duk_get_tval(thr, idx);
18380 if (tv != NULL) {
18381 return tv;
18382 }
18383 return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
18384}
18385
18386DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
18387 duk_uidx_t vs_size;
18388 duk_uidx_t uidx;
18389
18390 DUK_ASSERT_API_ENTRY(thr);
18391 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18392
18393 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18394 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18395 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
18396
18397 /* Use unsigned arithmetic to optimize comparison. */
18398 if (idx < 0) {
18399 uidx = vs_size + (duk_uidx_t) idx;
18400 } else {
18401 DUK_ASSERT(idx != DUK_INVALID_INDEX);
18402 uidx = (duk_uidx_t) idx;
18403 }
18404
18405 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18406 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18407
18408 if (DUK_LIKELY(uidx < vs_size)) {
18409 return thr->valstack_bottom + uidx;
18410 }
18411 DUK_ERROR_RANGE_INDEX(thr, idx);
18412 DUK_WO_NORETURN(return NULL;);
18413}
18414
18415/* Non-critical. */
18416DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) {
18417 DUK_ASSERT_API_ENTRY(thr);
18418 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18419
18420 return (duk_normalize_index(thr, idx) >= 0);
18421}
18422
18423/* Non-critical. */
18424DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
18425 DUK_ASSERT_API_ENTRY(thr);
18426 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18427
18428 if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
18429 DUK_ERROR_RANGE_INDEX(thr, idx);
18430 DUK_WO_NORETURN(return;);
18431 }
18432}
18433
18434/*
18435 * Value stack top handling
18436 */
18437
18438DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) {
18439 DUK_ASSERT_API_ENTRY(thr);
18440
18441 return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18442}
18443
18444/* Internal helper to get current top but to require a minimum top value
18445 * (TypeError if not met).
18446 */
18447DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) {
18448 duk_idx_t ret;
18449
18450 DUK_ASSERT_API_ENTRY(thr);
18451
18452 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
18453 if (DUK_UNLIKELY(ret < min_top)) {
18454 DUK_ERROR_TYPE_INVALID_ARGS(thr);
18455 DUK_WO_NORETURN(return 0;);
18456 }
18457 return ret;
18458}
18459
18460/* Set stack top within currently allocated range, but don't reallocate.
18461 * This is performance critical especially for call handling, so whenever
18462 * changing, profile and look at generated code.
18463 */
18464DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
18465 duk_uidx_t vs_size;
18466 duk_uidx_t vs_limit;
18467 duk_uidx_t uidx;
18468 duk_tval *tv;
18469
18470 DUK_ASSERT_API_ENTRY(thr);
18471 DUK_ASSERT(DUK_INVALID_INDEX < 0);
18472
18473 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18474 DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
18475 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18476 vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
18477
18478 if (idx < 0) {
18479 /* Negative indices are always within allocated stack but
18480 * must not go below zero index.
18481 */
18482 uidx = vs_size + (duk_uidx_t) idx;
18483 } else {
18484 /* Positive index can be higher than valstack top but must
18485 * not go above allocated stack (equality is OK).
18486 */
18487 uidx = (duk_uidx_t) idx;
18488 }
18489
18490 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18491 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18492 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
18493
18494#if defined(DUK_USE_VALSTACK_UNSAFE)
18495 DUK_ASSERT(uidx <= vs_limit);
18496 DUK_UNREF(vs_limit);
18497#else
18498 if (DUK_UNLIKELY(uidx > vs_limit)) {
18499 DUK_ERROR_RANGE_INDEX(thr, idx);
18500 DUK_WO_NORETURN(return;);
18501 }
18502#endif
18503 DUK_ASSERT(uidx <= vs_limit);
18504
18505 /* Handle change in value stack top. Respect value stack
18506 * initialization policy: 'undefined' above top. Note that
18507 * DECREF may cause a side effect that reallocates valstack,
18508 * so must relookup after DECREF.
18509 */
18510
18511 if (uidx >= vs_size) {
18512 /* Stack size increases or stays the same. */
18513#if defined(DUK_USE_ASSERTIONS)
18514 duk_uidx_t count;
18515
18516 count = uidx - vs_size;
18517 while (count != 0) {
18518 count--;
18519 tv = thr->valstack_top + count;
18520 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
18521 }
18522#endif
18523 thr->valstack_top = thr->valstack_bottom + uidx;
18524 } else {
18525 /* Stack size decreases. */
18526#if defined(DUK_USE_REFERENCE_COUNTING)
18527 duk_uidx_t count;
18528 duk_tval *tv_end;
18529
18530 count = vs_size - uidx;
18531 DUK_ASSERT(count > 0);
18532 tv = thr->valstack_top;
18533 tv_end = tv - count;
18534 DUK_ASSERT(tv > tv_end); /* Because count > 0. */
18535 do {
18536 tv--;
18537 DUK_ASSERT(tv >= thr->valstack_bottom);
18538 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
18539 } while (tv != tv_end);
18540 thr->valstack_top = tv_end;
18541 DUK_REFZERO_CHECK_FAST(thr);
18542#else /* DUK_USE_REFERENCE_COUNTING */
18543 duk_uidx_t count;
18544 duk_tval *tv_end;
18545
18546 count = vs_size - uidx;
18547 tv = thr->valstack_top;
18548 tv_end = tv - count;
18549 DUK_ASSERT(tv > tv_end);
18550 do {
18551 tv--;
18552 DUK_TVAL_SET_UNDEFINED(tv);
18553 } while (tv != tv_end);
18554 thr->valstack_top = tv_end;
18555#endif /* DUK_USE_REFERENCE_COUNTING */
18556 }
18557}
18558
18559/* Internal variant with a non-negative index and no runtime size checks. */
18560#if defined(DUK_USE_PREFER_SIZE)
18561DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
18562 DUK_ASSERT_API_ENTRY(thr);
18563
18564 duk_set_top(thr, idx);
18565}
18566#else /* DUK_USE_PREFER_SIZE */
18567DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
18568 duk_uidx_t uidx;
18569 duk_uidx_t vs_size;
18570 duk_tval *tv;
18571
18572 DUK_ASSERT_API_ENTRY(thr);
18573 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18574 DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
18575 DUK_ASSERT(idx >= 0);
18576 DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom));
18577
18578 /* XXX: byte arithmetic */
18579 uidx = (duk_uidx_t) idx;
18580 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18581
18582 if (uidx >= vs_size) {
18583 /* Stack size increases or stays the same. */
18584#if defined(DUK_USE_ASSERTIONS)
18585 duk_uidx_t count;
18586
18587 count = uidx - vs_size;
18588 while (count != 0) {
18589 count--;
18590 tv = thr->valstack_top + count;
18591 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
18592 }
18593#endif
18594 thr->valstack_top = thr->valstack_bottom + uidx;
18595 } else {
18596 /* Stack size decreases. */
18597#if defined(DUK_USE_REFERENCE_COUNTING)
18598 duk_uidx_t count;
18599 duk_tval *tv_end;
18600
18601 count = vs_size - uidx;
18602 DUK_ASSERT(count > 0);
18603 tv = thr->valstack_top;
18604 tv_end = tv - count;
18605 DUK_ASSERT(tv > tv_end); /* Because count > 0. */
18606 do {
18607 tv--;
18608 DUK_ASSERT(tv >= thr->valstack_bottom);
18609 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
18610 } while (tv != tv_end);
18611 thr->valstack_top = tv_end;
18612 DUK_REFZERO_CHECK_FAST(thr);
18613#else /* DUK_USE_REFERENCE_COUNTING */
18614 duk_uidx_t count;
18615 duk_tval *tv_end;
18616
18617 count = vs_size - uidx;
18618 tv = thr->valstack_top;
18619 tv_end = tv - count;
18620 DUK_ASSERT(tv > tv_end);
18621 do {
18622 tv--;
18623 DUK_TVAL_SET_UNDEFINED(tv);
18624 } while (tv != tv_end);
18625 thr->valstack_top = tv_end;
18626#endif /* DUK_USE_REFERENCE_COUNTING */
18627 }
18628}
18629#endif /* DUK_USE_PREFER_SIZE */
18630
18631/* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to
18632 * 'undefined' (doing nothing if idx_wipe_start == top). Indices are
18633 * positive and within value stack reserve. This is used by call handling.
18634 */
18635DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) {
18636 DUK_ASSERT_API_ENTRY(thr);
18637 DUK_ASSERT(top >= 0);
18638 DUK_ASSERT(idx_wipe_start >= 0);
18639 DUK_ASSERT(idx_wipe_start <= top);
18640 DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end);
18641 DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end);
18642
18643 duk_set_top_unsafe(thr, idx_wipe_start);
18644 duk_set_top_unsafe(thr, top);
18645}
18646
18647DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) {
18648 duk_idx_t ret;
18649
18650 DUK_ASSERT_API_ENTRY(thr);
18651
18652 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18653 if (DUK_UNLIKELY(ret < 0)) {
18654 /* Return invalid index; if caller uses this without checking
18655 * in another API call, the index won't map to a valid stack
18656 * entry.
18657 */
18658 return DUK_INVALID_INDEX;
18659 }
18660 return ret;
18661}
18662
18663/* Internal variant: call assumes there is at least one element on the value
18664 * stack frame; this is only asserted for.
18665 */
18666DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) {
18667 duk_idx_t ret;
18668
18669 DUK_ASSERT_API_ENTRY(thr);
18670
18671 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18672 return ret;
18673}
18674
18675DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
18676 duk_idx_t ret;
18677
18678 DUK_ASSERT_API_ENTRY(thr);
18679
18680 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18681 if (DUK_UNLIKELY(ret < 0)) {
18682 DUK_ERROR_RANGE_INDEX(thr, -1);
18683 DUK_WO_NORETURN(return 0;);
18684 }
18685 return ret;
18686}
18687
18688/*
18689 * Value stack resizing.
18690 *
18691 * This resizing happens above the current "top": the value stack can be
18692 * grown or shrunk, but the "top" is not affected. The value stack cannot
18693 * be resized to a size below the current reserve.
18694 *
18695 * The low level reallocation primitive must carefully recompute all value
18696 * stack pointers, and must also work if ALL pointers are NULL. The resize
18697 * is quite tricky because the valstack realloc may cause a mark-and-sweep,
18698 * which may run finalizers. Running finalizers may resize the valstack
18699 * recursively (the same value stack we're working on). So, after realloc
18700 * returns, we know that the valstack bottom, top, and reserve should still
18701 * be the same (there should not be live values above the "top"), but its
18702 * underlying size, alloc_end, and base pointer may have changed.
18703 *
18704 * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that
18705 * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
18706 */
18707
18708/* Low level valstack resize primitive, used for both grow and shrink. All
18709 * adjustments for slack etc have already been done. Doesn't throw but does
18710 * have allocation side effects.
18711 */
18712DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) {
18713 duk_tval *pre_valstack;
18714 duk_tval *pre_bottom;
18715 duk_tval *pre_top;
18716 duk_tval *pre_end;
18717 duk_tval *pre_alloc_end;
18718 duk_ptrdiff_t ptr_diff;
18719 duk_tval *new_valstack;
18720 duk_size_t new_alloc_size;
18721 duk_tval *tv_prev_alloc_end;
18722 duk_tval *p;
18723
18724 DUK_HTHREAD_ASSERT_VALID(thr);
18725 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
18726 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18727 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
18728 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18729 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
18730 DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */
18731 DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
18732
18733 /* Pre-realloc pointer copies for asserts and debug logs. */
18734 pre_valstack = thr->valstack;
18735 pre_bottom = thr->valstack_bottom;
18736 pre_top = thr->valstack_top;
18737 pre_end = thr->valstack_end;
18738 pre_alloc_end = thr->valstack_alloc_end;
18739
18740 DUK_UNREF(pre_valstack);
18741 DUK_UNREF(pre_bottom);
18742 DUK_UNREF(pre_top);
18743 DUK_UNREF(pre_end);
18744 DUK_UNREF(pre_alloc_end);
18745
18746 /* If finalizer torture enabled, force base pointer change every time
18747 * when it would be allowed.
18748 */
18749#if defined(DUK_USE_FINALIZER_TORTURE)
18750 if (thr->heap->pf_prevent_count == 0) {
18751 duk_hthread_valstack_torture_realloc(thr);
18752 }
18753#endif
18754
18755 /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with
18756 * a side effect changing the base pointer.
18757 */
18758 new_alloc_size = sizeof(duk_tval) * new_size;
18759 new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
18760 if (DUK_UNLIKELY(new_valstack == NULL)) {
18761 /* Because new_size != 0, if condition doesn't need to be
18762 * (new_valstack != NULL || new_size == 0).
18763 */
18764 DUK_ASSERT(new_size != 0);
18765 DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
18766 (unsigned long) new_size, (unsigned long) new_alloc_size));
18767 return 0;
18768 }
18769
18770 /* Debug log any changes in pointer(s) by side effects. These don't
18771 * necessarily imply any incorrect behavior, but should be rare in
18772 * practice.
18773 */
18774#if defined(DUK_USE_DEBUG)
18775 if (thr->valstack != pre_valstack) {
18776 DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p",
18777 (void *) pre_valstack, (void *) thr->valstack));
18778 }
18779 if (thr->valstack_bottom != pre_bottom) {
18780 DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p",
18781 (void *) pre_bottom, (void *) thr->valstack_bottom));
18782 }
18783 if (thr->valstack_top != pre_top) {
18784 DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p",
18785 (void *) pre_top, (void *) thr->valstack_top));
18786 }
18787 if (thr->valstack_end != pre_end) {
18788 DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p",
18789 (void *) pre_end, (void *) thr->valstack_end));
18790 }
18791 if (thr->valstack_alloc_end != pre_alloc_end) {
18792 DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p",
18793 (void *) pre_alloc_end, (void *) thr->valstack_alloc_end));
18794 }
18795#endif
18796
18797 /* Assertions: offsets for bottom, top, and end (reserve) must not
18798 * have changed even with side effects because they are always
18799 * restored in unwind. For alloc_end there's no guarantee: it may
18800 * have grown or shrunk (but remain above 'end').
18801 */
18802 DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack);
18803 DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack);
18804 DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack);
18805 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18806
18807 /* Write new pointers. Most pointers can be handled as a pointer
18808 * difference.
18809 */
18810 ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack);
18811 tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff);
18812 thr->valstack = new_valstack;
18813 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff);
18814 thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff);
18815 thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff);
18816 thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size);
18817
18818 /* Assertions: pointer sanity after pointer updates. */
18819 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
18820 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18821 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
18822 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18823
18824 DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): "
18825 "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), "
18826 "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);"
18827 " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)",
18828 (unsigned long) (pre_alloc_end - pre_valstack),
18829 (unsigned long) new_size,
18830 (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack),
18831 (unsigned long) new_alloc_size,
18832 (void *) pre_valstack, (void *) thr->valstack,
18833 (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack),
18834 (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack),
18835 (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack),
18836 (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack),
18837 (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end)));
18838
18839 /* If allocation grew, init any new slots to 'undefined'. */
18840 p = tv_prev_alloc_end;
18841 while (p < thr->valstack_alloc_end) {
18842 /* Never executed if new size is smaller. */
18843 DUK_TVAL_SET_UNDEFINED(p);
18844 p++;
18845 }
18846
18847 /* Assert for value stack initialization policy. */
18848#if defined(DUK_USE_ASSERTIONS)
18849 p = thr->valstack_top;
18850 while (p < thr->valstack_alloc_end) {
18851 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
18852 p++;
18853 }
18854#endif
18855
18856 return 1;
18857}
18858
18859DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) {
18860 duk_size_t min_size;
18861 duk_size_t new_size;
18862
18863 DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes);
18864 min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */
18865
18866#if defined(DUK_USE_VALSTACK_GROW_SHIFT)
18867 /* New size is minimum size plus a proportional slack, e.g. shift of
18868 * 2 means a 25% slack.
18869 */
18870 new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT);
18871#else
18872 /* New size is tight with no slack. This is sometimes preferred in
18873 * low memory environments.
18874 */
18875 new_size = min_size;
18876#endif
18877
18878 if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) {
18879 /* Note: may be triggered even if minimal new_size would not reach the limit,
18880 * plan limit accordingly.
18881 */
18882 if (throw_on_error) {
18883 DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
18884 DUK_WO_NORETURN(return 0;);
18885 }
18886 return 0;
18887 }
18888
18889 if (duk__resize_valstack(thr, new_size) == 0) {
18890 if (throw_on_error) {
18891 DUK_ERROR_ALLOC_FAILED(thr);
18892 DUK_WO_NORETURN(return 0;);
18893 }
18894 return 0;
18895 }
18896
18897 thr->valstack_end = thr->valstack + min_size;
18898 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18899
18900 return 1;
18901}
18902
18903/* Hot, inlined value stack grow check. Because value stack almost never
18904 * grows, the actual resize call is in a NOINLINE helper.
18905 */
18906DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) {
18907 duk_tval *tv;
18908
18909 tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
18910 if (DUK_LIKELY(thr->valstack_end >= tv)) {
18911 return;
18912 }
18913 if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
18914 /* Values in [valstack_top,valstack_alloc_end[ are initialized
18915 * to 'undefined' so we can just move the end pointer.
18916 */
18917 thr->valstack_end = tv;
18918 return;
18919 }
18920 (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/);
18921}
18922
18923/* Hot, inlined value stack grow check which doesn't throw. */
18924DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) {
18925 duk_tval *tv;
18926
18927 tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
18928 if (DUK_LIKELY(thr->valstack_end >= tv)) {
18929 return 1;
18930 }
18931 if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
18932 thr->valstack_end = tv;
18933 return 1;
18934 }
18935 return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/);
18936}
18937
18938/* Value stack shrink check, called from mark-and-sweep. */
18939DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) {
18940 duk_size_t alloc_bytes;
18941 duk_size_t reserve_bytes;
18942 duk_size_t shrink_bytes;
18943
18944 alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
18945 reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
18946 DUK_ASSERT(alloc_bytes >= reserve_bytes);
18947
18948 /* We're free to shrink the value stack allocation down to
18949 * reserve_bytes but not more. If 'snug' (emergency GC)
18950 * shrink whatever we can. Otherwise only shrink if the new
18951 * size would be considerably smaller.
18952 */
18953
18954#if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT)
18955 if (snug) {
18956 shrink_bytes = reserve_bytes;
18957 } else {
18958 duk_size_t proportion, slack;
18959
18960 /* Require that value stack shrinks by at least X% of its
18961 * current size. For example, shift of 2 means at least
18962 * 25%. The proportion is computed as bytes and may not
18963 * be a multiple of sizeof(duk_tval); that's OK here.
18964 */
18965 proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT;
18966 if (alloc_bytes - reserve_bytes < proportion) {
18967 /* Too little would be freed, do nothing. */
18968 return;
18969 }
18970
18971 /* Keep a slack after shrinking. The slack is again a
18972 * proportion of the current size (the proportion should
18973 * of course be smaller than the check proportion above).
18974 */
18975#if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT)
18976 DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT);
18977 slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT;
18978#else
18979 slack = 0;
18980#endif
18981 shrink_bytes = reserve_bytes +
18982 slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */
18983 }
18984#else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
18985 /* Always snug, useful in some low memory environments. */
18986 DUK_UNREF(snug);
18987 shrink_bytes = reserve_bytes;
18988#endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
18989
18990 DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)",
18991 (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes));
18992 DUK_ASSERT(shrink_bytes >= reserve_bytes);
18993 if (shrink_bytes >= alloc_bytes) {
18994 /* Skip if shrink target is same as current one (or higher,
18995 * though that shouldn't happen in practice).
18996 */
18997 return;
18998 }
18999 DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes);
19000
19001 DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug));
19002
19003 duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval));
19004}
19005
19006DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) {
19007 duk_size_t min_new_bytes;
19008
19009 DUK_ASSERT_API_ENTRY(thr);
19010 DUK_ASSERT(thr != NULL);
19011
19012 if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
19013 if (extra < 0) {
19014 /* Clamping to zero makes the API more robust to calling code
19015 * calculation errors.
19016 */
19017 extra = 0;
19018 } else {
19019 /* Cause grow check to fail without wrapping arithmetic. */
19020 extra = DUK_USE_VALSTACK_LIMIT;
19021 }
19022 }
19023
19024 min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
19025 sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
19026 return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
19027}
19028
19029DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) {
19030 duk_size_t min_new_bytes;
19031
19032 DUK_ASSERT_API_ENTRY(thr);
19033 DUK_ASSERT(thr != NULL);
19034
19035 if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
19036 if (extra < 0) {
19037 /* Clamping to zero makes the API more robust to calling code
19038 * calculation errors.
19039 */
19040 extra = 0;
19041 } else {
19042 /* Cause grow check to fail without wrapping arithmetic. */
19043 extra = DUK_USE_VALSTACK_LIMIT;
19044 }
19045 }
19046
19047 min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
19048 sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
19049 duk_valstack_grow_check_throw(thr, min_new_bytes);
19050}
19051
19052DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) {
19053 duk_size_t min_new_bytes;
19054
19055 DUK_ASSERT_API_ENTRY(thr);
19056
19057 if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
19058 if (top < 0) {
19059 /* Clamping to zero makes the API more robust to calling code
19060 * calculation errors.
19061 */
19062 top = 0;
19063 } else {
19064 /* Cause grow check to fail without wrapping arithmetic. */
19065 top = DUK_USE_VALSTACK_LIMIT;
19066 }
19067 }
19068
19069 DUK_ASSERT(top >= 0);
19070 min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
19071 sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
19072 return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
19073}
19074
19075DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) {
19076 duk_size_t min_new_bytes;
19077
19078 DUK_ASSERT_API_ENTRY(thr);
19079
19080 if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
19081 if (top < 0) {
19082 /* Clamping to zero makes the API more robust to calling code
19083 * calculation errors.
19084 */
19085 top = 0;
19086 } else {
19087 /* Cause grow check to fail without wrapping arithmetic. */
19088 top = DUK_USE_VALSTACK_LIMIT;
19089 }
19090 }
19091
19092 DUK_ASSERT(top >= 0);
19093 min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
19094 sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
19095 duk_valstack_grow_check_throw(thr, min_new_bytes);
19096}
19097
19098/*
19099 * Basic stack manipulation: swap, dup, insert, replace, etc
19100 */
19101
19102DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
19103 duk_tval *tv1;
19104 duk_tval *tv2;
19105 duk_tval tv_tmp;
19106
19107 DUK_ASSERT_API_ENTRY(thr);
19108
19109 tv1 = duk_require_tval(thr, idx1);
19110 DUK_ASSERT(tv1 != NULL);
19111 tv2 = duk_require_tval(thr, idx2);
19112 DUK_ASSERT(tv2 != NULL);
19113
19114 /* If tv1==tv2 this is a NOP, no check is needed */
19115 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
19116 DUK_TVAL_SET_TVAL(tv1, tv2);
19117 DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
19118}
19119
19120DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) {
19121 DUK_ASSERT_API_ENTRY(thr);
19122
19123 duk_swap(thr, idx, -1);
19124}
19125
19126DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) {
19127 duk_tval *tv_from;
19128 duk_tval *tv_to;
19129
19130 DUK_ASSERT_API_ENTRY(thr);
19131 DUK__CHECK_SPACE();
19132
19133 tv_from = duk_require_tval(thr, from_idx);
19134 tv_to = thr->valstack_top++;
19135 DUK_ASSERT(tv_from != NULL);
19136 DUK_ASSERT(tv_to != NULL);
19137 DUK_TVAL_SET_TVAL(tv_to, tv_from);
19138 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
19139}
19140
19141DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
19142#if defined(DUK_USE_PREFER_SIZE)
19143 duk_dup(thr, -1);
19144#else
19145 duk_tval *tv_from;
19146 duk_tval *tv_to;
19147
19148 DUK_ASSERT_API_ENTRY(thr);
19149 DUK__CHECK_SPACE();
19150
19151 if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
19152 DUK_ERROR_RANGE_INDEX(thr, -1);
19153 DUK_WO_NORETURN(return;);
19154 }
19155 tv_from = thr->valstack_top - 1;
19156 tv_to = thr->valstack_top++;
19157 DUK_ASSERT(tv_from != NULL);
19158 DUK_ASSERT(tv_to != NULL);
19159 DUK_TVAL_SET_TVAL(tv_to, tv_from);
19160 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
19161#endif
19162}
19163
19164DUK_INTERNAL void duk_dup_0(duk_hthread *thr) {
19165 DUK_ASSERT_API_ENTRY(thr);
19166 duk_dup(thr, 0);
19167}
19168DUK_INTERNAL void duk_dup_1(duk_hthread *thr) {
19169 DUK_ASSERT_API_ENTRY(thr);
19170 duk_dup(thr, 1);
19171}
19172DUK_INTERNAL void duk_dup_2(duk_hthread *thr) {
19173 DUK_ASSERT_API_ENTRY(thr);
19174 duk_dup(thr, 2);
19175}
19176DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) {
19177 DUK_ASSERT_API_ENTRY(thr);
19178 duk_dup(thr, -2);
19179}
19180DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) {
19181 DUK_ASSERT_API_ENTRY(thr);
19182 duk_dup(thr, -3);
19183}
19184DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) {
19185 DUK_ASSERT_API_ENTRY(thr);
19186 duk_dup(thr, -4);
19187}
19188
19189DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
19190 duk_tval *p;
19191 duk_tval *q;
19192 duk_tval tv_tmp;
19193 duk_size_t nbytes;
19194
19195 DUK_ASSERT_API_ENTRY(thr);
19196
19197 p = duk_require_tval(thr, to_idx);
19198 DUK_ASSERT(p != NULL);
19199 q = duk_require_tval(thr, -1);
19200 DUK_ASSERT(q != NULL);
19201
19202 DUK_ASSERT(q >= p);
19203
19204 /* nbytes
19205 * <--------->
19206 * [ ... | p | x | x | q ]
19207 * => [ ... | q | p | x | x ]
19208 */
19209
19210 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));
19211
19212 DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
19213 (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
19214
19215 /* No net refcount changes. No need to special case nbytes == 0
19216 * (p == q).
19217 */
19218 DUK_TVAL_SET_TVAL(&tv_tmp, q);
19219 duk_memmove((void *) (p + 1), (const void *) p, (size_t) nbytes);
19220 DUK_TVAL_SET_TVAL(p, &tv_tmp);
19221}
19222
19223DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
19224 DUK_ASSERT_API_ENTRY(thr);
19225 DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */
19226
19227 duk_push_undefined(thr);
19228 duk_insert(thr, idx);
19229}
19230
19231DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
19232 duk_tval *tv, *tv_end;
19233
19234 DUK_ASSERT_API_ENTRY(thr);
19235 DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */
19236 DUK_ASSERT(count >= 0);
19237
19238 tv = duk_reserve_gap(thr, idx, count);
19239 tv_end = tv + count;
19240 while (tv != tv_end) {
19241 DUK_TVAL_SET_UNDEFINED(tv);
19242 tv++;
19243 }
19244}
19245
19246DUK_EXTERNAL void duk_pull(duk_hthread *thr, duk_idx_t from_idx) {
19247 duk_tval *p;
19248 duk_tval *q;
19249 duk_tval tv_tmp;
19250 duk_size_t nbytes;
19251
19252 DUK_ASSERT_API_ENTRY(thr);
19253
19254 /* nbytes
19255 * <--------->
19256 * [ ... | x | x | p | y | y | q ]
19257 * => [ ... | x | x | y | y | q | p ]
19258 */
19259
19260 p = duk_require_tval(thr, from_idx);
19261 DUK_ASSERT(p != NULL);
19262 q = duk_require_tval(thr, -1);
19263 DUK_ASSERT(q != NULL);
19264
19265 DUK_ASSERT(q >= p);
19266
19267 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));
19268
19269 DUK_DDD(DUK_DDDPRINT("duk_pull: from_idx=%ld, p=%p, q=%p, nbytes=%lu",
19270 (long) from_idx, (void *) p, (void *) q, (unsigned long) nbytes));
19271
19272 /* No net refcount changes. No need to special case nbytes == 0
19273 * (p == q).
19274 */
19275 DUK_TVAL_SET_TVAL(&tv_tmp, p);
19276 duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes);
19277 DUK_TVAL_SET_TVAL(q, &tv_tmp);
19278}
19279
19280DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) {
19281 duk_tval *tv1;
19282 duk_tval *tv2;
19283 duk_tval tv_tmp;
19284
19285 DUK_ASSERT_API_ENTRY(thr);
19286
19287 tv1 = duk_require_tval(thr, -1);
19288 DUK_ASSERT(tv1 != NULL);
19289 tv2 = duk_require_tval(thr, to_idx);
19290 DUK_ASSERT(tv2 != NULL);
19291
19292 /* For tv1 == tv2, both pointing to stack top, the end result
19293 * is same as duk_pop(thr).
19294 */
19295 DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
19296 DUK_TVAL_SET_TVAL(tv2, tv1);
19297 DUK_TVAL_SET_UNDEFINED(tv1);
19298 thr->valstack_top--;
19299 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
19300}
19301
19302DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) {
19303 duk_tval *tv1;
19304 duk_tval *tv2;
19305
19306 DUK_ASSERT_API_ENTRY(thr);
19307
19308 tv1 = duk_require_tval(thr, from_idx);
19309 DUK_ASSERT(tv1 != NULL);
19310 tv2 = duk_require_tval(thr, to_idx);
19311 DUK_ASSERT(tv2 != NULL);
19312
19313 /* For tv1 == tv2, this is a no-op (no explicit check needed). */
19314 DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
19315}
19316
19317DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
19318 duk_tval *p;
19319 duk_tval *q;
19320#if defined(DUK_USE_REFERENCE_COUNTING)
19321 duk_tval tv_tmp;
19322#endif
19323 duk_size_t nbytes;
19324
19325 DUK_ASSERT_API_ENTRY(thr);
19326
19327 p = duk_require_tval(thr, idx);
19328 DUK_ASSERT(p != NULL);
19329 q = duk_require_tval(thr, -1);
19330 DUK_ASSERT(q != NULL);
19331
19332 DUK_ASSERT(q >= p);
19333
19334 /* nbytes zero size case
19335 * <--------->
19336 * [ ... | p | x | x | q ] [ ... | p==q ]
19337 * => [ ... | x | x | q ] [ ... ]
19338 */
19339
19340#if defined(DUK_USE_REFERENCE_COUNTING)
19341 /* use a temp: decref only when valstack reachable values are correct */
19342 DUK_TVAL_SET_TVAL(&tv_tmp, p);
19343#endif
19344
19345 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
19346 duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes);
19347
19348 DUK_TVAL_SET_UNDEFINED(q);
19349 thr->valstack_top--;
19350
19351#if defined(DUK_USE_REFERENCE_COUNTING)
19352 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
19353#endif
19354}
19355
19356DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) {
19357 DUK_ASSERT_API_ENTRY(thr);
19358
19359 duk_remove(thr, idx); /* XXX: no optimization for now */
19360}
19361
19362DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) {
19363 DUK_ASSERT_API_ENTRY(thr);
19364
19365 duk_remove(thr, -2);
19366}
19367
19368DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
19369#if defined(DUK_USE_PREFER_SIZE)
19370 /* XXX: maybe too slow even when preferring size? */
19371 DUK_ASSERT_API_ENTRY(thr);
19372 DUK_ASSERT(count >= 0);
19373 DUK_ASSERT(idx >= 0);
19374
19375 while (count-- > 0) {
19376 duk_remove(thr, idx);
19377 }
19378#else /* DUK_USE_PREFER_SIZE */
19379 duk_tval *tv_src;
19380 duk_tval *tv_dst;
19381 duk_tval *tv_newtop;
19382 duk_tval *tv;
19383 duk_size_t bytes;
19384
19385 DUK_ASSERT_API_ENTRY(thr);
19386 DUK_ASSERT(count >= 0);
19387 DUK_ASSERT(idx >= 0);
19388
19389 tv_dst = thr->valstack_bottom + idx;
19390 DUK_ASSERT(tv_dst <= thr->valstack_top);
19391 tv_src = tv_dst + count;
19392 DUK_ASSERT(tv_src <= thr->valstack_top);
19393 bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
19394
19395 for (tv = tv_dst; tv < tv_src; tv++) {
19396 DUK_TVAL_DECREF_NORZ(thr, tv);
19397 }
19398
19399 duk_memmove((void *) tv_dst, (const void *) tv_src, bytes);
19400
19401 tv_newtop = thr->valstack_top - count;
19402 for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
19403 DUK_TVAL_SET_UNDEFINED(tv);
19404 }
19405 thr->valstack_top = tv_newtop;
19406
19407 /* When not preferring size, only NORZ macros are used; caller
19408 * is expected to DUK_REFZERO_CHECK().
19409 */
19410#endif /* DUK_USE_PREFER_SIZE */
19411}
19412
19413DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
19414 DUK_ASSERT_API_ENTRY(thr);
19415
19416 duk_remove_n(thr, idx, count); /* XXX: no optimization for now */
19417}
19418
19419/*
19420 * Stack slice primitives
19421 */
19422
19423DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) {
19424 void *src;
19425 duk_size_t nbytes;
19426 duk_tval *p;
19427 duk_tval *q;
19428
19429 /* XXX: several pointer comparison issues here */
19430
19431 DUK_ASSERT_API_ENTRY(to_thr);
19432 DUK_CTX_ASSERT_VALID(to_thr);
19433 DUK_CTX_ASSERT_VALID(from_thr);
19434 DUK_ASSERT(to_thr->heap == from_thr->heap);
19435
19436 if (DUK_UNLIKELY(to_thr == from_thr)) {
19437 DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
19438 DUK_WO_NORETURN(return;);
19439 }
19440 if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
19441 /* Maximum value check ensures 'nbytes' won't wrap below.
19442 * Also handles negative count.
19443 */
19444 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
19445 DUK_WO_NORETURN(return;);
19446 }
19447 DUK_ASSERT(count >= 0);
19448
19449 nbytes = sizeof(duk_tval) * (duk_size_t) count;
19450 if (DUK_UNLIKELY(nbytes == 0)) {
19451 return;
19452 }
19453 DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
19454 if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) {
19455 DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
19456 DUK_WO_NORETURN(return;);
19457 }
19458 src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
19459 if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) {
19460 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
19461 DUK_WO_NORETURN(return;);
19462 }
19463
19464 /* Copy values (no overlap even if to_thr == from_thr; that's not
19465 * allowed now anyway).
19466 */
19467 DUK_ASSERT(nbytes > 0);
19468 duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
19469
19470 p = to_thr->valstack_top;
19471 to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
19472
19473 if (is_copy) {
19474 /* Incref copies, keep originals. */
19475 q = to_thr->valstack_top;
19476 while (p < q) {
19477 DUK_TVAL_INCREF(to_thr, p); /* no side effects */
19478 p++;
19479 }
19480 } else {
19481 /* No net refcount change. */
19482 p = from_thr->valstack_top;
19483 q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
19484 from_thr->valstack_top = q;
19485
19486 while (p > q) {
19487 p--;
19488 DUK_TVAL_SET_UNDEFINED(p);
19489 /* XXX: fast primitive to set a bunch of values to UNDEFINED */
19490 }
19491 }
19492}
19493
19494/* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a
19495 * pointer to the gap. Values in the gap are garbage and MUST be initialized by
19496 * the caller before any side effects may occur. The caller must ensure there's
19497 * enough stack reserve for 'count' values.
19498 */
19499DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) {
19500 duk_tval *tv_src;
19501 duk_tval *tv_dst;
19502 duk_size_t gap_bytes;
19503 duk_size_t copy_bytes;
19504
19505 /* Caller is responsible for ensuring there's enough preallocated
19506 * value stack.
19507 */
19508 DUK_ASSERT_API_ENTRY(thr);
19509 DUK_ASSERT(count >= 0);
19510 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count);
19511
19512 tv_src = thr->valstack_bottom + idx_base;
19513 gap_bytes = (duk_size_t) count * sizeof(duk_tval);
19514 tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
19515 copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
19516 thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
19517 duk_memmove((void *) tv_dst, (const void *) tv_src, copy_bytes);
19518
19519 /* Values in the gap are left as garbage: caller must fill them in
19520 * and INCREF them before any side effects.
19521 */
19522 return tv_src;
19523}
19524
19525/*
19526 * Get/opt/require
19527 */
19528
19529DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
19530 duk_tval *tv;
19531
19532 DUK_ASSERT_API_ENTRY(thr);
19533
19534 tv = duk_get_tval_or_unused(thr, idx);
19535 DUK_ASSERT(tv != NULL);
19536 if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
19537 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
19538 DUK_WO_NORETURN(return;);
19539 }
19540}
19541
19542DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
19543 duk_tval *tv;
19544
19545 DUK_ASSERT_API_ENTRY(thr);
19546
19547 tv = duk_get_tval_or_unused(thr, idx);
19548 DUK_ASSERT(tv != NULL);
19549 if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
19550 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
19551 DUK_WO_NORETURN(return;);
19552 }
19553}
19554
19555DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19556 duk_bool_t ret;
19557 duk_tval *tv;
19558
19559 DUK_CTX_ASSERT_VALID(thr);
19560
19561 tv = duk_get_tval_or_unused(thr, idx);
19562 DUK_ASSERT(tv != NULL);
19563 if (DUK_TVAL_IS_BOOLEAN(tv)) {
19564 ret = DUK_TVAL_GET_BOOLEAN(tv);
19565 DUK_ASSERT(ret == 0 || ret == 1);
19566 } else {
19567 ret = def_value;
19568 /* Not guaranteed to be 0 or 1. */
19569 }
19570
19571 return ret;
19572}
19573
19574DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) {
19575 DUK_ASSERT_API_ENTRY(thr);
19576
19577 return duk__get_boolean_raw(thr, idx, 0); /* default: false */
19578}
19579
19580DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19581 DUK_ASSERT_API_ENTRY(thr);
19582
19583 return duk__get_boolean_raw(thr, idx, def_value);
19584}
19585
19586DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
19587 duk_tval *tv;
19588 duk_bool_t ret;
19589
19590 DUK_ASSERT_API_ENTRY(thr);
19591
19592 tv = duk_get_tval_or_unused(thr, idx);
19593 DUK_ASSERT(tv != NULL);
19594 if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) {
19595 ret = DUK_TVAL_GET_BOOLEAN(tv);
19596 DUK_ASSERT(ret == 0 || ret == 1);
19597 return ret;
19598 } else {
19599 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
19600 DUK_WO_NORETURN(return 0;);
19601 }
19602}
19603
19604DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19605 DUK_ASSERT_API_ENTRY(thr);
19606
19607 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19608 return def_value;
19609 }
19610 return duk_require_boolean(thr, idx);
19611}
19612
19613DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19614 duk_double_union ret;
19615 duk_tval *tv;
19616
19617 DUK_CTX_ASSERT_VALID(thr);
19618
19619 tv = duk_get_tval_or_unused(thr, idx);
19620 DUK_ASSERT(tv != NULL);
19621#if defined(DUK_USE_FASTINT)
19622 if (DUK_TVAL_IS_FASTINT(tv)) {
19623 ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */
19624 }
19625 else
19626#endif
19627 if (DUK_TVAL_IS_DOUBLE(tv)) {
19628 /* When using packed duk_tval, number must be in NaN-normalized form
19629 * for it to be a duk_tval, so no need to normalize. NOP for unpacked
19630 * duk_tval.
19631 */
19632 ret.d = DUK_TVAL_GET_DOUBLE(tv);
19633 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
19634 } else {
19635 ret.d = def_value;
19636 /* Default value (including NaN) may not be normalized. */
19637 }
19638
19639 return ret.d;
19640}
19641
19642DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) {
19643 DUK_ASSERT_API_ENTRY(thr);
19644 return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */
19645}
19646
19647DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19648 DUK_ASSERT_API_ENTRY(thr);
19649 return duk__get_number_raw(thr, idx, def_value);
19650}
19651
19652DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
19653 duk_tval *tv;
19654 duk_double_union ret;
19655
19656 DUK_ASSERT_API_ENTRY(thr);
19657
19658 tv = duk_get_tval_or_unused(thr, idx);
19659 DUK_ASSERT(tv != NULL);
19660 if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
19661 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
19662 DUK_WO_NORETURN(return 0.0;);
19663 }
19664
19665 ret.d = DUK_TVAL_GET_NUMBER(tv);
19666
19667 /* When using packed duk_tval, number must be in NaN-normalized form
19668 * for it to be a duk_tval, so no need to normalize. NOP for unpacked
19669 * duk_tval.
19670 */
19671 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
19672 return ret.d;
19673}
19674
19675DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19676 DUK_ASSERT_API_ENTRY(thr);
19677
19678 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19679 /* User provided default is not NaN normalized. */
19680 return def_value;
19681 }
19682 return duk_require_number(thr, idx);
19683}
19684
19685DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) {
19686 DUK_ASSERT_API_ENTRY(thr);
19687
19688 return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
19689}
19690
19691DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) {
19692 DUK_ASSERT_API_ENTRY(thr);
19693
19694 return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
19695}
19696
19697DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
19698 DUK_ASSERT_API_ENTRY(thr);
19699
19700 return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/);
19701}
19702
19703DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
19704 DUK_ASSERT_API_ENTRY(thr);
19705
19706 return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/);
19707}
19708
19709DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) {
19710 DUK_ASSERT_API_ENTRY(thr);
19711
19712 return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/);
19713}
19714
19715DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) {
19716 DUK_ASSERT_API_ENTRY(thr);
19717
19718 return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/);
19719}
19720
19721DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
19722 DUK_ASSERT_API_ENTRY(thr);
19723
19724 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19725 return def_value;
19726 }
19727 return duk_require_int(thr, idx);
19728}
19729
19730DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
19731 DUK_ASSERT_API_ENTRY(thr);
19732
19733 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19734 return def_value;
19735 }
19736 return duk_require_uint(thr, idx);
19737}
19738
19739DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19740 duk_hstring *h;
19741 const char *ret;
19742 duk_size_t len;
19743
19744 DUK_ASSERT_API_ENTRY(thr);
19745
19746 h = duk_get_hstring(thr, idx);
19747 if (h != NULL) {
19748 len = DUK_HSTRING_GET_BYTELEN(h);
19749 ret = (const char *) DUK_HSTRING_GET_DATA(h);
19750 } else {
19751 len = 0;
19752 ret = NULL;
19753 }
19754
19755 if (out_len != NULL) {
19756 *out_len = len;
19757 }
19758 return ret;
19759}
19760
19761DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19762 duk_hstring *h;
19763
19764 DUK_ASSERT_API_ENTRY(thr);
19765
19766 h = duk_require_hstring(thr, idx);
19767 DUK_ASSERT(h != NULL);
19768 if (out_len) {
19769 *out_len = DUK_HSTRING_GET_BYTELEN(h);
19770 }
19771 return (const char *) DUK_HSTRING_GET_DATA(h);
19772}
19773
19774DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19775 duk_hstring *h;
19776
19777 DUK_ASSERT_API_ENTRY(thr);
19778
19779 h = duk_require_hstring_notsymbol(thr, idx);
19780 DUK_ASSERT(h != NULL);
19781 if (out_len) {
19782 *out_len = DUK_HSTRING_GET_BYTELEN(h);
19783 }
19784 return (const char *) DUK_HSTRING_GET_DATA(h);
19785}
19786
19787DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) {
19788 duk_hstring *h;
19789
19790 DUK_ASSERT_API_ENTRY(thr);
19791
19792 h = duk_get_hstring(thr, idx);
19793 if (h != NULL) {
19794 return (const char *) DUK_HSTRING_GET_DATA(h);
19795 } else {
19796 return NULL;
19797 }
19798}
19799
19800DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
19801 DUK_ASSERT_API_ENTRY(thr);
19802
19803 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19804 if (out_len != NULL) {
19805 *out_len = def_len;
19806 }
19807 return def_ptr;
19808 }
19809 return duk_require_lstring(thr, idx, out_len);
19810}
19811
19812DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) {
19813 DUK_ASSERT_API_ENTRY(thr);
19814
19815 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19816 return def_ptr;
19817 }
19818 return duk_require_string(thr, idx);
19819}
19820
19821DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) {
19822 duk_hstring *h;
19823 const char *ret;
19824 duk_size_t len;
19825
19826 DUK_ASSERT_API_ENTRY(thr);
19827
19828 h = duk_get_hstring(thr, idx);
19829 if (h != NULL) {
19830 len = DUK_HSTRING_GET_BYTELEN(h);
19831 ret = (const char *) DUK_HSTRING_GET_DATA(h);
19832 } else {
19833 len = def_len;
19834 ret = def_ptr;
19835 }
19836
19837 if (out_len != NULL) {
19838 *out_len = len;
19839 }
19840 return ret;
19841}
19842
19843DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) {
19844 duk_hstring *h;
19845
19846 DUK_ASSERT_API_ENTRY(thr);
19847
19848 h = duk_get_hstring(thr, idx);
19849 if (h != NULL) {
19850 return (const char *) DUK_HSTRING_GET_DATA(h);
19851 } else {
19852 return def_value;
19853 }
19854}
19855
19856DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19857 duk_hstring *h;
19858
19859 DUK_ASSERT_API_ENTRY(thr);
19860
19861 h = duk_get_hstring_notsymbol(thr, idx);
19862 if (h) {
19863 return (const char *) DUK_HSTRING_GET_DATA(h);
19864 } else {
19865 return NULL;
19866 }
19867}
19868
19869DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) {
19870 DUK_ASSERT_API_ENTRY(thr);
19871
19872 return duk_require_lstring(thr, idx, NULL);
19873}
19874
19875DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19876 duk_hstring *h;
19877
19878 DUK_ASSERT_API_ENTRY(thr);
19879
19880 h = duk_require_hstring_notsymbol(thr, idx);
19881 DUK_ASSERT(h != NULL);
19882 return (const char *) DUK_HSTRING_GET_DATA(h);
19883}
19884
19885DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
19886 duk_tval *tv;
19887
19888 DUK_ASSERT_API_ENTRY(thr);
19889
19890 tv = duk_get_tval_or_unused(thr, idx);
19891 DUK_ASSERT(tv != NULL);
19892 if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
19893 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
19894 DUK_WO_NORETURN(return;);
19895 }
19896}
19897
19898DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19899 duk_tval *tv;
19900 void *p;
19901
19902 DUK_CTX_ASSERT_VALID(thr);
19903
19904 tv = duk_get_tval_or_unused(thr, idx);
19905 DUK_ASSERT(tv != NULL);
19906 if (!DUK_TVAL_IS_POINTER(tv)) {
19907 return def_value;
19908 }
19909
19910 p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
19911 return p;
19912}
19913
19914DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) {
19915 DUK_ASSERT_API_ENTRY(thr);
19916 return duk__get_pointer_raw(thr, idx, NULL /*def_value*/);
19917}
19918
19919DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19920 DUK_ASSERT_API_ENTRY(thr);
19921
19922 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19923 return def_value;
19924 }
19925 return duk_require_pointer(thr, idx);
19926}
19927
19928DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19929 DUK_ASSERT_API_ENTRY(thr);
19930 return duk__get_pointer_raw(thr, idx, def_value);
19931}
19932
19933DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
19934 duk_tval *tv;
19935 void *p;
19936
19937 DUK_ASSERT_API_ENTRY(thr);
19938
19939 /* Note: here we must be wary of the fact that a pointer may be
19940 * valid and be a NULL.
19941 */
19942 tv = duk_get_tval_or_unused(thr, idx);
19943 DUK_ASSERT(tv != NULL);
19944 if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
19945 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
19946 DUK_WO_NORETURN(return NULL;);
19947 }
19948 p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
19949 return p;
19950}
19951
19952#if 0 /*unused*/
19953DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) {
19954 duk_tval *tv;
19955 duk_heaphdr *h;
19956
19957 DUK_ASSERT_API_ENTRY(thr);
19958
19959 tv = duk_get_tval_or_unused(thr, idx);
19960 DUK_ASSERT(tv != NULL);
19961 if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
19962 return NULL;
19963 }
19964
19965 h = DUK_TVAL_GET_HEAPHDR(tv);
19966 DUK_ASSERT(h != NULL);
19967 return (void *) h;
19968}
19969#endif
19970
19971DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) {
19972 duk_hbuffer *h;
19973 void *ret;
19974 duk_size_t len;
19975 duk_tval *tv;
19976
19977 DUK_CTX_ASSERT_VALID(thr);
19978
19979 if (out_size != NULL) {
19980 *out_size = 0;
19981 }
19982
19983 tv = duk_get_tval_or_unused(thr, idx);
19984 DUK_ASSERT(tv != NULL);
19985 if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) {
19986 h = DUK_TVAL_GET_BUFFER(tv);
19987 DUK_ASSERT(h != NULL);
19988
19989 len = DUK_HBUFFER_GET_SIZE(h);
19990 ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
19991 } else {
19992 if (throw_flag) {
19993 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
19994 DUK_WO_NORETURN(return NULL;);
19995 }
19996 len = def_size;
19997 ret = def_ptr;
19998 }
19999
20000 if (out_size != NULL) {
20001 *out_size = len;
20002 }
20003 return ret;
20004}
20005
20006DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
20007 DUK_ASSERT_API_ENTRY(thr);
20008
20009 return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
20010}
20011
20012DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
20013 DUK_ASSERT_API_ENTRY(thr);
20014
20015 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
20016 if (out_size != NULL) {
20017 *out_size = def_size;
20018 }
20019 return def_ptr;
20020 }
20021 return duk_require_buffer(thr, idx, out_size);
20022}
20023
20024DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) {
20025 DUK_ASSERT_API_ENTRY(thr);
20026
20027 return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
20028}
20029
20030DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
20031 DUK_ASSERT_API_ENTRY(thr);
20032
20033 return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
20034}
20035
20036/* Get the active buffer data area for a plain buffer or a buffer object.
20037 * Return NULL if the the value is not a buffer. Note that a buffer may
20038 * have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
20039 * argument allows caller to detect this reliably.
20040 */
20041DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
20042 duk_tval *tv;
20043
20044 DUK_ASSERT_API_ENTRY(thr);
20045
20046 if (out_isbuffer != NULL) {
20047 *out_isbuffer = 0;
20048 }
20049 if (out_size != NULL) {
20050 *out_size = def_size;
20051 }
20052
20053 tv = duk_get_tval_or_unused(thr, idx);
20054 DUK_ASSERT(tv != NULL);
20055
20056 if (DUK_TVAL_IS_BUFFER(tv)) {
20057 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
20058 DUK_ASSERT(h != NULL);
20059 if (out_size != NULL) {
20060 *out_size = DUK_HBUFFER_GET_SIZE(h);
20061 }
20062 if (out_isbuffer != NULL) {
20063 *out_isbuffer = 1;
20064 }
20065 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
20066 }
20067#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
20068 else if (DUK_TVAL_IS_OBJECT(tv)) {
20069 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
20070 DUK_ASSERT(h != NULL);
20071 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
20072 /* XXX: this is probably a useful shared helper: for a
20073 * duk_hbufobj, get a validated buffer pointer/length.
20074 */
20075 duk_hbufobj *h_bufobj = (duk_hbufobj *) h;
20076 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
20077
20078 if (h_bufobj->buf != NULL &&
20079 DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
20080 duk_uint8_t *p;
20081
20082 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
20083 if (out_size != NULL) {
20084 *out_size = (duk_size_t) h_bufobj->length;
20085 }
20086 if (out_isbuffer != NULL) {
20087 *out_isbuffer = 1;
20088 }
20089 return (void *) (p + h_bufobj->offset);
20090 }
20091 /* if slice not fully valid, treat as error */
20092 }
20093 }
20094#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
20095
20096 if (throw_flag) {
20097 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
20098 DUK_WO_NORETURN(return NULL;);
20099 }
20100 return def_ptr;
20101}
20102
20103DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
20104 DUK_ASSERT_API_ENTRY(thr);
20105 return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
20106}
20107
20108DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
20109 DUK_ASSERT_API_ENTRY(thr);
20110 return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
20111}
20112
20113DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) {
20114 DUK_ASSERT_API_ENTRY(thr);
20115
20116 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
20117 if (out_size != NULL) {
20118 *out_size = def_size;
20119 }
20120 return def_ptr;
20121 }
20122 return duk_require_buffer_data(thr, idx, out_size);
20123}
20124
20125DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
20126 DUK_ASSERT_API_ENTRY(thr);
20127 return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
20128}
20129
20130/* Raw helper for getting a value from the stack, checking its tag.
20131 * The tag cannot be a number because numbers don't have an internal
20132 * tag in the packed representation.
20133 */
20134
20135DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) {
20136 duk_tval *tv;
20137 duk_heaphdr *ret;
20138
20139 DUK_CTX_ASSERT_VALID(thr);
20140
20141 tv = duk_get_tval_or_unused(thr, idx);
20142 DUK_ASSERT(tv != NULL);
20143 if (DUK_TVAL_GET_TAG(tv) != tag) {
20144 return (duk_heaphdr *) NULL;
20145 }
20146
20147 ret = DUK_TVAL_GET_HEAPHDR(tv);
20148 DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
20149 return ret;
20150
20151}
20152
20153DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) {
20154 DUK_ASSERT_API_ENTRY(thr);
20155 return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
20156}
20157
20158DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
20159 duk_hstring *h;
20160
20161 DUK_ASSERT_API_ENTRY(thr);
20162
20163 h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
20164 if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) {
20165 return NULL;
20166 }
20167 return h;
20168}
20169
20170DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
20171 duk_hstring *h;
20172
20173 DUK_ASSERT_API_ENTRY(thr);
20174
20175 h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
20176 if (DUK_UNLIKELY(h == NULL)) {
20177 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
20178 DUK_WO_NORETURN(return NULL;);
20179 }
20180 return h;
20181}
20182
20183DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
20184 duk_hstring *h;
20185
20186 DUK_ASSERT_API_ENTRY(thr);
20187
20188 h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
20189 if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
20190 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
20191 DUK_WO_NORETURN(return NULL;);
20192 }
20193 return h;
20194}
20195
20196DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) {
20197 DUK_ASSERT_API_ENTRY(thr);
20198 return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20199}
20200
20201DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
20202 duk_hobject *h;
20203
20204 DUK_ASSERT_API_ENTRY(thr);
20205
20206 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20207 if (DUK_UNLIKELY(h == NULL)) {
20208 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
20209 DUK_WO_NORETURN(return NULL;);
20210 }
20211 return h;
20212}
20213
20214DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) {
20215 DUK_ASSERT_API_ENTRY(thr);
20216 return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
20217}
20218
20219DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
20220 duk_hbuffer *h;
20221
20222 DUK_ASSERT_API_ENTRY(thr);
20223
20224 h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
20225 if (DUK_UNLIKELY(h == NULL)) {
20226 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
20227 DUK_WO_NORETURN(return NULL;);
20228 }
20229 return h;
20230}
20231
20232DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) {
20233 duk_hobject *h;
20234
20235 DUK_ASSERT_API_ENTRY(thr);
20236
20237 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20238 if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) {
20239 h = NULL;
20240 }
20241 return (duk_hthread *) h;
20242}
20243
20244DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
20245 duk_hobject *h;
20246
20247 DUK_ASSERT_API_ENTRY(thr);
20248
20249 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20250 if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
20251 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
20252 DUK_WO_NORETURN(return NULL;);
20253 }
20254 return (duk_hthread *) h;
20255}
20256
20257DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
20258 duk_hobject *h;
20259
20260 DUK_ASSERT_API_ENTRY(thr);
20261
20262 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20263 if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) {
20264 h = NULL;
20265 }
20266 return (duk_hcompfunc *) h;
20267}
20268
20269DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
20270 duk_hobject *h;
20271
20272 DUK_ASSERT_API_ENTRY(thr);
20273
20274 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20275 if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
20276 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
20277 DUK_WO_NORETURN(return NULL;);
20278 }
20279 return (duk_hcompfunc *) h;
20280}
20281
20282DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
20283 duk_hobject *h;
20284
20285 DUK_ASSERT_API_ENTRY(thr);
20286
20287 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20288 if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) {
20289 h = NULL;
20290 }
20291 return (duk_hnatfunc *) h;
20292}
20293
20294DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
20295 duk_hobject *h;
20296
20297 DUK_ASSERT_API_ENTRY(thr);
20298
20299 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20300 if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
20301 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
20302 DUK_WO_NORETURN(return NULL;);
20303 }
20304 return (duk_hnatfunc *) h;
20305}
20306
20307DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) {
20308 duk_tval *tv;
20309 duk_hobject *h;
20310 duk_hnatfunc *f;
20311
20312 DUK_ASSERT_API_ENTRY(thr);
20313
20314 tv = duk_get_tval_or_unused(thr, idx);
20315 DUK_ASSERT(tv != NULL);
20316 if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
20317 return NULL;
20318 }
20319 h = DUK_TVAL_GET_OBJECT(tv);
20320 DUK_ASSERT(h != NULL);
20321
20322 if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) {
20323 return NULL;
20324 }
20325 DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h));
20326 f = (duk_hnatfunc *) h;
20327
20328 return f->func;
20329}
20330
20331DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
20332 DUK_ASSERT_API_ENTRY(thr);
20333
20334 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
20335 return def_value;
20336 }
20337 return duk_require_c_function(thr, idx);
20338}
20339
20340DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
20341 duk_c_function ret;
20342
20343 DUK_ASSERT_API_ENTRY(thr);
20344
20345 ret = duk_get_c_function(thr, idx);
20346 if (ret != NULL) {
20347 return ret;
20348 }
20349
20350 return def_value;
20351}
20352
20353DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) {
20354 duk_c_function ret;
20355
20356 DUK_ASSERT_API_ENTRY(thr);
20357
20358 ret = duk_get_c_function(thr, idx);
20359 if (DUK_UNLIKELY(!ret)) {
20360 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
20361 DUK_WO_NORETURN(return ret;);
20362 }
20363 return ret;
20364}
20365
20366DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
20367 DUK_ASSERT_API_ENTRY(thr);
20368 if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
20369 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
20370 DUK_WO_NORETURN(return;);
20371 }
20372}
20373
20374DUK_EXTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
20375 duk_hobject *h;
20376
20377 DUK_ASSERT_API_ENTRY(thr);
20378
20379 h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
20380 if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
20381 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
20382 DUK_WO_NORETURN(return;);
20383 }
20384 /* Lightfuncs (h == NULL) are constructable. */
20385}
20386
20387DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) {
20388 DUK_ASSERT_API_ENTRY(thr);
20389
20390 return duk_get_hthread(thr, idx);
20391}
20392
20393DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) {
20394 DUK_ASSERT_API_ENTRY(thr);
20395
20396 return duk_require_hthread(thr, idx);
20397}
20398
20399DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
20400 DUK_ASSERT_API_ENTRY(thr);
20401
20402 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
20403 return def_value;
20404 }
20405 return duk_require_context(thr, idx);
20406}
20407
20408DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
20409 duk_hthread *ret;
20410
20411 DUK_ASSERT_API_ENTRY(thr);
20412
20413 ret = duk_get_context(thr, idx);
20414 if (ret != NULL) {
20415 return ret;
20416 }
20417
20418 return def_value;
20419}
20420
20421DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) {
20422 duk_tval *tv;
20423 void *ret;
20424
20425 DUK_ASSERT_API_ENTRY(thr);
20426
20427 tv = duk_get_tval_or_unused(thr, idx);
20428 DUK_ASSERT(tv != NULL);
20429 if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
20430 return (void *) NULL;
20431 }
20432
20433 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
20434 DUK_ASSERT(ret != NULL);
20435 return ret;
20436}
20437
20438DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) {
20439 DUK_ASSERT_API_ENTRY(thr);
20440
20441 if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
20442 return def_value;
20443 }
20444 return duk_require_heapptr(thr, idx);
20445}
20446
20447DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
20448 void *ret;
20449
20450 DUK_ASSERT_API_ENTRY(thr);
20451
20452 ret = duk_get_heapptr(thr, idx);
20453 if (ret != NULL) {
20454 return ret;
20455 }
20456
20457 return def_value;
20458}
20459
20460DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
20461 duk_tval *tv;
20462 void *ret;
20463
20464 DUK_ASSERT_API_ENTRY(thr);
20465
20466 tv = duk_get_tval_or_unused(thr, idx);
20467 DUK_ASSERT(tv != NULL);
20468 if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
20469 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
20470 DUK_WO_NORETURN(return NULL;);
20471 }
20472
20473 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
20474 DUK_ASSERT(ret != NULL);
20475 return ret;
20476}
20477
20478/* Internal helper for getting/requiring a duk_hobject with possible promotion. */
20479DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20480 duk_uint_t val_mask;
20481 duk_hobject *res;
20482
20483 DUK_CTX_ASSERT_VALID(thr);
20484
20485 res = duk_get_hobject(thr, idx); /* common case, not promoted */
20486 if (DUK_LIKELY(res != NULL)) {
20487 DUK_ASSERT(res != NULL);
20488 return res;
20489 }
20490
20491 val_mask = duk_get_type_mask(thr, idx);
20492 if (val_mask & type_mask) {
20493 if (type_mask & DUK_TYPE_MASK_PROMOTE) {
20494 res = duk_to_hobject(thr, idx);
20495 DUK_ASSERT(res != NULL);
20496 return res;
20497 } else {
20498 return NULL; /* accept without promoting */
20499 }
20500 }
20501
20502 if (type_mask & DUK_TYPE_MASK_THROW) {
20503 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
20504 DUK_WO_NORETURN(return NULL;);
20505 }
20506 return NULL;
20507}
20508
20509/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the
20510 * supplied 'type_mask', promote it to an object and return the duk_hobject *.
20511 * This is useful for call sites which want an object but also accept a plain
20512 * buffer and/or a lightfunc which gets automatically promoted to an object.
20513 * Return value is NULL if value is neither an object nor a plain type allowed
20514 * by the mask.
20515 */
20516DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20517 DUK_ASSERT_API_ENTRY(thr);
20518 return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
20519}
20520
20521/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
20522 * returning a NULL.
20523 */
20524DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20525 DUK_ASSERT_API_ENTRY(thr);
20526 return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
20527}
20528
20529/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
20530 * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError.
20531 */
20532DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20533 DUK_ASSERT_API_ENTRY(thr);
20534 return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW);
20535}
20536
20537DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
20538 duk_hobject *h;
20539
20540 DUK_ASSERT_API_ENTRY(thr);
20541 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
20542 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
20543
20544 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20545 if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) {
20546 h = NULL;
20547 }
20548 return h;
20549}
20550
20551DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
20552 duk_hobject *h;
20553
20554 DUK_ASSERT_API_ENTRY(thr);
20555 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
20556 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
20557
20558 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20559 if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) {
20560 duk_hstring *h_class;
20561 h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
20562 DUK_UNREF(h_class);
20563
20564 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
20565 DUK_WO_NORETURN(return NULL;);
20566 }
20567 return h;
20568}
20569
20570DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) {
20571 duk_tval *tv;
20572
20573 DUK_ASSERT_API_ENTRY(thr);
20574
20575 tv = duk_get_tval_or_unused(thr, idx);
20576 DUK_ASSERT(tv != NULL);
20577
20578 switch (DUK_TVAL_GET_TAG(tv)) {
20579 case DUK_TAG_UNDEFINED:
20580 case DUK_TAG_NULL:
20581 case DUK_TAG_BOOLEAN:
20582 case DUK_TAG_POINTER:
20583 return 0;
20584#if defined(DUK_USE_PREFER_SIZE)
20585 /* String and buffer have a virtual non-configurable .length property
20586 * which is within size_t range so it can be looked up without specific
20587 * type checks. Lightfuncs inherit from %NativeFunctionPrototype%
20588 * which provides an inherited .length accessor; it could be overwritten
20589 * to produce unexpected types or values, but just number convert and
20590 * duk_size_t cast for now.
20591 */
20592 case DUK_TAG_STRING:
20593 case DUK_TAG_BUFFER:
20594 case DUK_TAG_LIGHTFUNC: {
20595 duk_size_t ret;
20596 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20597 ret = (duk_size_t) duk_to_number_m1(thr);
20598 duk_pop_unsafe(thr);
20599 return ret;
20600 }
20601#else /* DUK_USE_PREFER_SIZE */
20602 case DUK_TAG_STRING: {
20603 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
20604 DUK_ASSERT(h != NULL);
20605 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
20606 return 0;
20607 }
20608 return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
20609 }
20610 case DUK_TAG_BUFFER: {
20611 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
20612 DUK_ASSERT(h != NULL);
20613 return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
20614 }
20615 case DUK_TAG_LIGHTFUNC: {
20616 /* We could look up the length from the lightfunc duk_tval,
20617 * but since Duktape 2.2 lightfunc .length comes from
20618 * %NativeFunctionPrototype% which can be overridden, so
20619 * look up the property explicitly.
20620 */
20621 duk_size_t ret;
20622 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20623 ret = (duk_size_t) duk_to_number_m1(thr);
20624 duk_pop_unsafe(thr);
20625 return ret;
20626 }
20627#endif /* DUK_USE_PREFER_SIZE */
20628 case DUK_TAG_OBJECT: {
20629 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
20630 DUK_ASSERT(h != NULL);
20631 return (duk_size_t) duk_hobject_get_length(thr, h);
20632 }
20633#if defined(DUK_USE_FASTINT)
20634 case DUK_TAG_FASTINT:
20635#endif
20636 default:
20637 /* number or 'unused' */
20638 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv));
20639 return 0;
20640 }
20641
20642 DUK_UNREACHABLE();
20643}
20644
20645/*
20646 * duk_known_xxx() helpers
20647 *
20648 * Used internally when we're 100% sure that a certain index is valid and
20649 * contains an object of a certain type. For example, if we duk_push_object()
20650 * we can then safely duk_known_hobject(thr, -1). These helpers just assert
20651 * for the index and type, and if the assumptions are not valid, memory unsafe
20652 * behavior happens.
20653 */
20654
20655DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) {
20656 duk_tval *tv;
20657 duk_heaphdr *h;
20658
20659 DUK_CTX_ASSERT_VALID(thr);
20660 if (idx < 0) {
20661 tv = thr->valstack_top + idx;
20662 } else {
20663 tv = thr->valstack_bottom + idx;
20664 }
20665 DUK_ASSERT(tv >= thr->valstack_bottom);
20666 DUK_ASSERT(tv < thr->valstack_top);
20667 h = DUK_TVAL_GET_HEAPHDR(tv);
20668 DUK_ASSERT(h != NULL);
20669 return h;
20670}
20671
20672DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) {
20673 DUK_ASSERT_API_ENTRY(thr);
20674 DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
20675 return (duk_hstring *) duk__known_heaphdr(thr, idx);
20676}
20677
20678DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) {
20679 DUK_ASSERT_API_ENTRY(thr);
20680 DUK_ASSERT(duk_get_hobject(thr, idx) != NULL);
20681 return (duk_hobject *) duk__known_heaphdr(thr, idx);
20682}
20683
20684DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) {
20685 DUK_ASSERT_API_ENTRY(thr);
20686 DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL);
20687 return (duk_hbuffer *) duk__known_heaphdr(thr, idx);
20688}
20689
20690DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
20691 DUK_ASSERT_API_ENTRY(thr);
20692 DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL);
20693 return (duk_hcompfunc *) duk__known_heaphdr(thr, idx);
20694}
20695
20696DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
20697 DUK_ASSERT_API_ENTRY(thr);
20698 DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL);
20699 return (duk_hnatfunc *) duk__known_heaphdr(thr, idx);
20700}
20701
20702DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) {
20703 DUK_ASSERT_API_ENTRY(thr);
20704
20705 idx = duk_normalize_index(thr, idx);
20706 duk_push_uint(thr, (duk_uint_t) len);
20707 duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20708}
20709
20710/*
20711 * Conversions and coercions
20712 *
20713 * The conversion/coercions are in-place operations on the value stack.
20714 * Some operations are implemented here directly, while others call a
20715 * helper in duk_js_ops.c after validating arguments.
20716 */
20717
20718/* E5 Section 8.12.8 */
20719
20720DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) {
20721 if (duk_get_prop_stridx(thr, idx, func_stridx)) {
20722 /* [ ... func ] */
20723 if (duk_is_callable(thr, -1)) {
20724 duk_dup(thr, idx); /* -> [ ... func this ] */
20725 duk_call_method(thr, 0); /* -> [ ... retval ] */
20726 if (duk_is_primitive(thr, -1)) {
20727 duk_replace(thr, idx);
20728 return 1;
20729 }
20730 /* [ ... retval ]; popped below */
20731 }
20732 }
20733 duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */
20734 return 0;
20735}
20736
20737DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) {
20738 duk_tval *tv;
20739
20740 DUK_ASSERT_API_ENTRY(thr);
20741
20742 tv = duk_require_tval(thr, idx);
20743 DUK_ASSERT(tv != NULL);
20744 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
20745}
20746
20747DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
20748 duk_tval *tv;
20749
20750 DUK_ASSERT_API_ENTRY(thr);
20751
20752 tv = duk_require_tval(thr, idx);
20753 DUK_ASSERT(tv != NULL);
20754 DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
20755}
20756
20757/* E5 Section 9.1 */
20758DUK_LOCAL const char * const duk__toprim_hint_strings[3] = {
20759 "default", "string", "number"
20760};
20761DUK_LOCAL void duk__to_primitive_helper(duk_hthread *thr, duk_idx_t idx, duk_int_t hint, duk_bool_t check_symbol) {
20762 /* Inline initializer for coercers[] is not allowed by old compilers like BCC. */
20763 duk_small_uint_t coercers[2];
20764
20765 DUK_ASSERT_API_ENTRY(thr);
20766 DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
20767
20768 idx = duk_require_normalize_index(thr, idx);
20769
20770 /* If already primitive, return as is. */
20771 if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
20772 DUK_TYPE_MASK_LIGHTFUNC |
20773 DUK_TYPE_MASK_BUFFER)) {
20774 DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
20775 return;
20776 }
20777
20778 /* @@toPrimitive lookup. Also do for plain buffers and lightfuncs
20779 * which mimic objects.
20780 */
20781 if (check_symbol && duk_get_method_stridx(thr, idx, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)) {
20782 DUK_ASSERT(hint >= 0 && (duk_size_t) hint < sizeof(duk__toprim_hint_strings) / sizeof(const char *));
20783 duk_dup(thr, idx);
20784 duk_push_string(thr, duk__toprim_hint_strings[hint]);
20785 duk_call_method(thr, 1); /* [ ... method value hint ] -> [ ... res] */
20786 if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
20787 DUK_TYPE_MASK_LIGHTFUNC |
20788 DUK_TYPE_MASK_BUFFER)) {
20789 goto fail;
20790 }
20791 duk_replace(thr, idx);
20792 return;
20793 }
20794
20795 /* Objects are coerced based on E5 specification.
20796 * Lightfuncs are coerced because they behave like
20797 * objects even if they're internally a primitive
20798 * type. Same applies to plain buffers, which behave
20799 * like ArrayBuffer objects since Duktape 2.x.
20800 */
20801
20802 /* Hint magic for Date is unnecessary in ES2015 because of
20803 * Date.prototype[@@toPrimitive]. However, it is needed if
20804 * symbol support is not enabled.
20805 */
20806#if defined(DUK_USE_SYMBOL_BUILTIN)
20807 if (hint == DUK_HINT_NONE) {
20808 hint = DUK_HINT_NUMBER;
20809 }
20810#else /* DUK_USE_SYMBOL_BUILTIN */
20811 if (hint == DUK_HINT_NONE) {
20812 duk_small_uint_t class_number;
20813
20814 class_number = duk_get_class_number(thr, idx);
20815 if (class_number == DUK_HOBJECT_CLASS_DATE) {
20816 hint = DUK_HINT_STRING;
20817 } else {
20818 hint = DUK_HINT_NUMBER;
20819 }
20820 }
20821#endif /* DUK_USE_SYMBOL_BUILTIN */
20822
20823 coercers[0] = DUK_STRIDX_VALUE_OF;
20824 coercers[1] = DUK_STRIDX_TO_STRING;
20825 if (hint == DUK_HINT_STRING) {
20826 coercers[0] = DUK_STRIDX_TO_STRING;
20827 coercers[1] = DUK_STRIDX_VALUE_OF;
20828 }
20829
20830 if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) {
20831 DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
20832 return;
20833 }
20834
20835 if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) {
20836 DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
20837 return;
20838 }
20839
20840 fail:
20841 DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
20842 DUK_WO_NORETURN(return;);
20843}
20844
20845DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
20846 duk__to_primitive_helper(thr, idx, hint, 1 /*check_symbol*/);
20847}
20848
20849#if defined(DUK_USE_SYMBOL_BUILTIN)
20850DUK_INTERNAL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
20851 duk__to_primitive_helper(thr, idx, hint, 0 /*check_symbol*/);
20852}
20853#endif
20854
20855/* E5 Section 9.2 */
20856DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
20857 duk_tval *tv;
20858 duk_bool_t val;
20859
20860 DUK_ASSERT_API_ENTRY(thr);
20861
20862 idx = duk_require_normalize_index(thr, idx);
20863 tv = DUK_GET_TVAL_POSIDX(thr, idx);
20864 DUK_ASSERT(tv != NULL);
20865
20866 val = duk_js_toboolean(tv);
20867 DUK_ASSERT(val == 0 || val == 1);
20868
20869 /* Note: no need to re-lookup tv, conversion is side effect free. */
20870 DUK_ASSERT(tv != NULL);
20871 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
20872 return val;
20873}
20874
20875DUK_INTERNAL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr) {
20876 duk_tval *tv;
20877 duk_bool_t val;
20878
20879 DUK_ASSERT_API_ENTRY(thr);
20880
20881 tv = duk_require_tval(thr, -1);
20882 DUK_ASSERT(tv != NULL);
20883
20884 val = duk_js_toboolean(tv);
20885 DUK_ASSERT(val == 0 || val == 1);
20886
20887 duk_pop_unsafe(thr);
20888 return val;
20889}
20890
20891DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
20892 duk_tval *tv;
20893 duk_double_t d;
20894
20895 DUK_ASSERT_API_ENTRY(thr);
20896
20897 /* XXX: No need to normalize; the whole operation could be inlined here to
20898 * avoid 'tv' re-lookup.
20899 */
20900 idx = duk_require_normalize_index(thr, idx);
20901 tv = DUK_GET_TVAL_POSIDX(thr, idx);
20902 DUK_ASSERT(tv != NULL);
20903 d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */
20904
20905 /* ToNumber() may have side effects so must relookup 'tv'. */
20906 tv = DUK_GET_TVAL_POSIDX(thr, idx);
20907 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
20908 return d;
20909}
20910
20911DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) {
20912 DUK_ASSERT_API_ENTRY(thr);
20913 return duk_to_number(thr, -1);
20914}
20915DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) {
20916 DUK_ASSERT_API_ENTRY(thr);
20917 return duk_to_number(thr, -2);
20918}
20919
20920DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) {
20921#if defined(DUK_USE_PREFER_SIZE)
20922 duk_double_t res;
20923
20924 DUK_ASSERT_API_ENTRY(thr);
20925
20926 duk_push_tval(thr, tv);
20927 res = duk_to_number_m1(thr);
20928 duk_pop_unsafe(thr);
20929 return res;
20930#else
20931 duk_double_t res;
20932 duk_tval *tv_dst;
20933
20934 DUK_ASSERT_API_ENTRY(thr);
20935 DUK__ASSERT_SPACE();
20936
20937 tv_dst = thr->valstack_top++;
20938 DUK_TVAL_SET_TVAL(tv_dst, tv);
20939 DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */
20940 res = duk_to_number_m1(thr); /* invalidates tv_dst */
20941
20942 tv_dst = --thr->valstack_top;
20943 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst));
20944 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */
20945 DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */
20946
20947 return res;
20948#endif
20949}
20950
20951/* XXX: combine all the integer conversions: they share everything
20952 * but the helper function for coercion.
20953 */
20954
20955typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
20956
20957DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) {
20958 duk_tval *tv;
20959 duk_double_t d;
20960
20961 DUK_CTX_ASSERT_VALID(thr);
20962
20963 tv = duk_require_tval(thr, idx);
20964 DUK_ASSERT(tv != NULL);
20965
20966#if defined(DUK_USE_FASTINT)
20967 /* If argument is a fastint, guarantee that it remains one.
20968 * There's no downgrade check for other cases.
20969 */
20970 if (DUK_TVAL_IS_FASTINT(tv)) {
20971 /* XXX: Unnecessary conversion back and forth. */
20972 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
20973 }
20974#endif
20975 d = coerce_func(thr, tv);
20976
20977 /* XXX: fastint? */
20978
20979 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
20980 tv = duk_require_tval(thr, idx);
20981 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
20982 return d;
20983}
20984
20985DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) {
20986 /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
20987 * API return value coercion: custom.
20988 */
20989 DUK_ASSERT_API_ENTRY(thr);
20990 (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
20991 return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
20992}
20993
20994DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) {
20995 /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
20996 * API return value coercion: custom.
20997 */
20998 DUK_ASSERT_API_ENTRY(thr);
20999 (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
21000 return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
21001}
21002
21003DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) {
21004 duk_tval *tv;
21005 duk_int32_t ret;
21006
21007 DUK_ASSERT_API_ENTRY(thr);
21008
21009 tv = duk_require_tval(thr, idx);
21010 DUK_ASSERT(tv != NULL);
21011 ret = duk_js_toint32(thr, tv);
21012
21013 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
21014 tv = duk_require_tval(thr, idx);
21015 DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */
21016 return ret;
21017}
21018
21019DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) {
21020 duk_tval *tv;
21021 duk_uint32_t ret;
21022
21023 DUK_ASSERT_API_ENTRY(thr);
21024
21025 tv = duk_require_tval(thr, idx);
21026 DUK_ASSERT(tv != NULL);
21027 ret = duk_js_touint32(thr, tv);
21028
21029 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
21030 tv = duk_require_tval(thr, idx);
21031 DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
21032 return ret;
21033}
21034
21035DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) {
21036 duk_tval *tv;
21037 duk_uint16_t ret;
21038
21039 DUK_ASSERT_API_ENTRY(thr);
21040
21041 tv = duk_require_tval(thr, idx);
21042 DUK_ASSERT(tv != NULL);
21043 ret = duk_js_touint16(thr, tv);
21044
21045 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
21046 tv = duk_require_tval(thr, idx);
21047 DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
21048 return ret;
21049}
21050
21051#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21052/* Special coercion for Uint8ClampedArray. */
21053DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) {
21054 duk_double_t d;
21055 duk_double_t t;
21056 duk_uint8_t ret;
21057
21058 DUK_ASSERT_API_ENTRY(thr);
21059
21060 /* XXX: Simplify this algorithm, should be possible to come up with
21061 * a shorter and faster algorithm by inspecting IEEE representation
21062 * directly.
21063 */
21064
21065 d = duk_to_number(thr, idx);
21066 if (d <= 0.0) {
21067 return 0;
21068 } else if (d >= 255) {
21069 return 255;
21070 } else if (DUK_ISNAN(d)) {
21071 /* Avoid NaN-to-integer coercion as it is compiler specific. */
21072 return 0;
21073 }
21074
21075 t = d - DUK_FLOOR(d);
21076 if (duk_double_equals(t, 0.5)) {
21077 /* Exact halfway, round to even. */
21078 ret = (duk_uint8_t) d;
21079 ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
21080 * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
21081 */
21082 } else {
21083 /* Not halfway, round to nearest. */
21084 ret = (duk_uint8_t) (d + 0.5);
21085 }
21086 return ret;
21087}
21088#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21089
21090DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
21091 DUK_ASSERT_API_ENTRY(thr);
21092
21093 (void) duk_to_string(thr, idx);
21094 DUK_ASSERT(duk_is_string(thr, idx));
21095 return duk_require_lstring(thr, idx, out_len);
21096}
21097
21098DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) {
21099 DUK_CTX_ASSERT_VALID(thr);
21100 DUK_UNREF(udata);
21101
21102 (void) duk_to_string(thr, -1);
21103 return 1;
21104}
21105
21106DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
21107 DUK_ASSERT_API_ENTRY(thr);
21108
21109 idx = duk_require_normalize_index(thr, idx);
21110
21111 /* We intentionally ignore the duk_safe_call() return value and only
21112 * check the output type. This way we don't also need to check that
21113 * the returned value is indeed a string in the success case.
21114 */
21115
21116 duk_dup(thr, idx);
21117 (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
21118 if (!duk_is_string(thr, -1)) {
21119 /* Error: try coercing error to string once. */
21120 (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
21121 if (!duk_is_string(thr, -1)) {
21122 /* Double error */
21123 duk_pop_unsafe(thr);
21124 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
21125 } else {
21126 ;
21127 }
21128 } else {
21129 /* String; may be a symbol, accepted. */
21130 ;
21131 }
21132 DUK_ASSERT(duk_is_string(thr, -1));
21133
21134 duk_replace(thr, idx);
21135 DUK_ASSERT(duk_get_string(thr, idx) != NULL);
21136 return duk_get_lstring(thr, idx, out_len);
21137}
21138
21139DUK_EXTERNAL const char *duk_to_stacktrace(duk_hthread *thr, duk_idx_t idx) {
21140 DUK_ASSERT_API_ENTRY(thr);
21141 idx = duk_require_normalize_index(thr, idx);
21142
21143 /* The expected argument to the call is an Error object. The stack
21144 * trace is extracted without an inheritance-based instanceof check
21145 * so that one can also extract the stack trace of a foreign error
21146 * created in another Realm. Accept only a string .stack property.
21147 */
21148 if (duk_is_object(thr, idx)) {
21149 (void) duk_get_prop_string(thr, idx, "stack");
21150 if (duk_is_string(thr, -1)) {
21151 duk_replace(thr, idx);
21152 } else {
21153 duk_pop(thr);
21154 }
21155 }
21156
21157 return duk_to_string(thr, idx);
21158}
21159
21160DUK_LOCAL duk_ret_t duk__safe_to_stacktrace_raw(duk_hthread *thr, void *udata) {
21161 DUK_CTX_ASSERT_VALID(thr);
21162 DUK_UNREF(udata);
21163
21164 (void) duk_to_stacktrace(thr, -1);
21165
21166 return 1;
21167}
21168
21169DUK_EXTERNAL const char *duk_safe_to_stacktrace(duk_hthread *thr, duk_idx_t idx) {
21170 duk_int_t rc;
21171
21172 DUK_ASSERT_API_ENTRY(thr);
21173 idx = duk_require_normalize_index(thr, idx);
21174
21175 duk_dup(thr, idx);
21176 rc = duk_safe_call(thr, duk__safe_to_stacktrace_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
21177 if (rc != 0) {
21178 /* Coercion failed. Try to coerce the coercion itself error
21179 * to a stack trace once. If that also fails, return a fixed,
21180 * preallocated 'Error' string to avoid potential infinite loop.
21181 */
21182 rc = duk_safe_call(thr, duk__safe_to_stacktrace_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
21183 if (rc != 0) {
21184 duk_pop_unsafe(thr);
21185 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
21186 }
21187 }
21188 duk_replace(thr, idx);
21189
21190 return duk_get_string(thr, idx);
21191}
21192
21193DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) {
21194 duk_hstring *h;
21195
21196 DUK_ASSERT_API_ENTRY(thr);
21197
21198 duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
21199 h = duk_get_hstring(thr, idx);
21200 if (h == NULL) {
21201 /* The "is string?" check may seem unnecessary, but as things
21202 * are duk_to_hstring() invokes ToString() which fails for
21203 * symbols. But since symbols are already strings for Duktape
21204 * C API, we check for that before doing the coercion.
21205 */
21206 h = duk_to_hstring(thr, idx);
21207 }
21208 DUK_ASSERT(h != NULL);
21209 return h;
21210}
21211
21212#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
21213DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
21214 DUK_ASSERT_API_ENTRY(thr);
21215
21216 (void) duk_safe_to_string(thr, idx);
21217 DUK_ASSERT(duk_is_string(thr, idx));
21218 DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
21219 return duk_known_hstring(thr, idx);
21220}
21221#endif
21222
21223/* Push Object.prototype.toString() output for 'tv'. */
21224DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) {
21225 duk_hobject *h_obj;
21226 duk_small_uint_t classnum;
21227 duk_small_uint_t stridx;
21228 duk_tval tv_tmp;
21229
21230 DUK_ASSERT_API_ENTRY(thr);
21231 DUK_ASSERT(tv != NULL);
21232
21233 /* Stabilize 'tv', duk_push_literal() may trigger side effects. */
21234 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
21235 tv = &tv_tmp;
21236
21237 /* Conceptually for any non-undefined/null value we should do a
21238 * ToObject() coercion and look up @@toStringTag (from the object
21239 * prototype) to see if a custom result should be used, with the
21240 * exception of Arrays which are handled specially first.
21241 *
21242 * We'd like to avoid the actual conversion, but even for primitive
21243 * types the prototype may have @@toStringTag. What's worse, the
21244 * @@toStringTag property may be a getter that must get the object
21245 * coerced value (not the prototype) as its 'this' binding.
21246 *
21247 * For now, do an actual object coercion. This could be avoided by
21248 * doing a side effect free lookup to see if a getter would be invoked.
21249 * If not, the value can be read directly and the object coercion could
21250 * be avoided. This may not be worth it in practice, because
21251 * Object.prototype.toString() is usually not performance critical.
21252 */
21253
21254 duk_push_literal(thr, "[object "); /* -> [ ... "[object" ] */
21255
21256 switch (DUK_TVAL_GET_TAG(tv)) {
21257 case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
21258 case DUK_TAG_UNDEFINED: {
21259 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_UNDEFINED);
21260 goto finish;
21261 }
21262 case DUK_TAG_NULL: {
21263 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_NULL);
21264 goto finish;
21265 }
21266 }
21267
21268 duk_push_tval(thr, tv);
21269 tv = NULL; /* Invalidated by ToObject(). */
21270 h_obj = duk_to_hobject(thr, -1);
21271 DUK_ASSERT(h_obj != NULL);
21272 if (duk_js_isarray_hobject(h_obj)) {
21273 stridx = DUK_STRIDX_UC_ARRAY;
21274 } else {
21275 /* [ ... "[object" obj ] */
21276
21277#if defined(DUK_USE_SYMBOL_BUILTIN)
21278 /* XXX: better handling with avoid_side_effects == 1; lookup tval
21279 * without Proxy or getter side effects, and use it in sanitized
21280 * form if it's a string.
21281 */
21282 if (!avoid_side_effects) {
21283 (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG);
21284 if (duk_is_string_notsymbol(thr, -1)) {
21285 duk_remove_m2(thr);
21286 goto finish;
21287 }
21288 duk_pop_unsafe(thr);
21289 }
21290#else
21291 DUK_UNREF(avoid_side_effects);
21292#endif
21293
21294 classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
21295 stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
21296 }
21297 duk_pop_unsafe(thr);
21298 duk_push_hstring_stridx(thr, stridx);
21299
21300 finish:
21301 /* [ ... "[object" tag ] */
21302 duk_push_literal(thr, "]");
21303 duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */
21304}
21305
21306/* XXX: other variants like uint, u32 etc */
21307DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
21308 duk_tval *tv;
21309 duk_tval tv_tmp;
21310 duk_double_t d, dmin, dmax;
21311 duk_int_t res;
21312 duk_bool_t clamped = 0;
21313
21314 DUK_ASSERT_API_ENTRY(thr);
21315
21316 tv = duk_require_tval(thr, idx);
21317 DUK_ASSERT(tv != NULL);
21318 d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
21319
21320 dmin = (duk_double_t) minval;
21321 dmax = (duk_double_t) maxval;
21322
21323 if (d < dmin) {
21324 clamped = 1;
21325 res = minval;
21326 d = dmin;
21327 } else if (d > dmax) {
21328 clamped = 1;
21329 res = maxval;
21330 d = dmax;
21331 } else {
21332 res = (duk_int_t) d;
21333 }
21334 DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
21335 /* 'd' and 'res' agree here */
21336
21337 /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
21338 tv = duk_get_tval(thr, idx);
21339 DUK_ASSERT(tv != NULL); /* not popped by side effect */
21340 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
21341#if defined(DUK_USE_FASTINT)
21342#if (DUK_INT_MAX <= 0x7fffffffL)
21343 DUK_TVAL_SET_I32(tv, res);
21344#else
21345 /* Clamping needed if duk_int_t is 64 bits. */
21346 if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
21347 DUK_TVAL_SET_FASTINT(tv, res);
21348 } else {
21349 DUK_TVAL_SET_NUMBER(tv, d);
21350 }
21351#endif
21352#else
21353 DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */
21354#endif
21355 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
21356
21357 if (out_clamped) {
21358 *out_clamped = clamped;
21359 } else {
21360 /* coerced value is updated to value stack even when RangeError thrown */
21361 if (clamped) {
21362 DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
21363 DUK_WO_NORETURN(return 0;);
21364 }
21365 }
21366
21367 return res;
21368}
21369
21370DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
21371 duk_bool_t dummy;
21372
21373 DUK_ASSERT_API_ENTRY(thr);
21374
21375 return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy);
21376}
21377
21378DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
21379 DUK_ASSERT_API_ENTRY(thr);
21380 return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
21381}
21382
21383DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
21384 duk_tval *tv;
21385
21386 DUK_ASSERT_API_ENTRY(thr);
21387
21388 idx = duk_require_normalize_index(thr, idx);
21389 tv = DUK_GET_TVAL_POSIDX(thr, idx);
21390 DUK_ASSERT(tv != NULL);
21391
21392 switch (DUK_TVAL_GET_TAG(tv)) {
21393 case DUK_TAG_UNDEFINED: {
21394 duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED);
21395 break;
21396 }
21397 case DUK_TAG_NULL: {
21398 duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
21399 break;
21400 }
21401 case DUK_TAG_BOOLEAN: {
21402 if (DUK_TVAL_GET_BOOLEAN(tv)) {
21403 duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE);
21404 } else {
21405 duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE);
21406 }
21407 break;
21408 }
21409 case DUK_TAG_STRING: {
21410 /* Nop for actual strings, TypeError for Symbols.
21411 * Because various internals rely on ToString() coercion of
21412 * internal strings, -allow- (NOP) string coercion for hidden
21413 * symbols.
21414 */
21415#if 1
21416 duk_hstring *h;
21417 h = DUK_TVAL_GET_STRING(tv);
21418 DUK_ASSERT(h != NULL);
21419 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
21420 DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
21421 DUK_WO_NORETURN(goto skip_replace;);
21422 } else {
21423 goto skip_replace;
21424 }
21425#else
21426 goto skip_replace;
21427#endif
21428 break;
21429 }
21430 case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
21431 case DUK_TAG_OBJECT: {
21432 /* Plain buffers: go through ArrayBuffer.prototype.toString()
21433 * for coercion.
21434 *
21435 * Symbol objects: duk_to_primitive() results in a plain symbol
21436 * value, and duk_to_string() then causes a TypeError.
21437 */
21438 duk_to_primitive(thr, idx, DUK_HINT_STRING);
21439 DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */
21440 DUK_ASSERT(!duk_is_object(thr, idx));
21441 return duk_to_string(thr, idx); /* Note: recursive call */
21442 }
21443 case DUK_TAG_POINTER: {
21444 void *ptr = DUK_TVAL_GET_POINTER(tv);
21445 if (ptr != NULL) {
21446 duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr);
21447 } else {
21448 /* Represent a null pointer as 'null' to be consistent with
21449 * the JX format variant. Native '%p' format for a NULL
21450 * pointer may be e.g. '(nil)'.
21451 */
21452 duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
21453 }
21454 break;
21455 }
21456 case DUK_TAG_LIGHTFUNC: {
21457 /* Should match Function.prototype.toString() */
21458 duk_push_lightfunc_tostring(thr, tv);
21459 break;
21460 }
21461#if defined(DUK_USE_FASTINT)
21462 case DUK_TAG_FASTINT:
21463#endif
21464 default: {
21465 /* number */
21466 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21467 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21468 duk_push_tval(thr, tv);
21469 duk_numconv_stringify(thr,
21470 10 /*radix*/,
21471 0 /*precision:shortest*/,
21472 0 /*force_exponential*/);
21473 break;
21474 }
21475 }
21476
21477 duk_replace(thr, idx);
21478
21479 skip_replace:
21480 DUK_ASSERT(duk_is_string(thr, idx));
21481 return duk_require_string(thr, idx);
21482}
21483
21484DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) {
21485 duk_hstring *ret;
21486
21487 DUK_ASSERT_API_ENTRY(thr);
21488
21489 duk_to_string(thr, idx);
21490 ret = duk_get_hstring(thr, idx);
21491 DUK_ASSERT(ret != NULL);
21492 return ret;
21493}
21494
21495DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) {
21496 DUK_ASSERT_API_ENTRY(thr);
21497 return duk_to_hstring(thr, -1);
21498}
21499
21500DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) {
21501 duk_hstring *ret;
21502
21503 DUK_ASSERT_API_ENTRY(thr);
21504
21505 ret = duk_get_hstring(thr, idx);
21506 if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) {
21507 return ret;
21508 }
21509 return duk_to_hstring(thr, idx);
21510}
21511
21512/* Convert a plain buffer or any buffer object into a string, using the buffer
21513 * bytes 1:1 in the internal string representation. For views the active byte
21514 * slice (not element slice interpreted as an initializer) is used. This is
21515 * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a
21516 * string with the same bytes as in the buffer but rather (usually)
21517 * '[object ArrayBuffer]'.
21518 */
21519DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) {
21520 void *ptr_src;
21521 duk_size_t len;
21522 const char *res;
21523
21524 DUK_ASSERT_API_ENTRY(thr);
21525
21526 idx = duk_require_normalize_index(thr, idx);
21527
21528 ptr_src = duk_require_buffer_data(thr, idx, &len);
21529 DUK_ASSERT(ptr_src != NULL || len == 0);
21530
21531 res = duk_push_lstring(thr, (const char *) ptr_src, len);
21532 duk_replace(thr, idx);
21533 return res;
21534}
21535
21536DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
21537 duk_hbuffer *h_buf;
21538 const duk_uint8_t *src_data;
21539 duk_size_t src_size;
21540 duk_uint8_t *dst_data;
21541
21542 DUK_ASSERT_API_ENTRY(thr);
21543
21544 idx = duk_require_normalize_index(thr, idx);
21545
21546 h_buf = duk_get_hbuffer(thr, idx);
21547 if (h_buf != NULL) {
21548 /* Buffer is kept as is, with the fixed/dynamic nature of the
21549 * buffer only changed if requested. An external buffer
21550 * is converted into a non-external dynamic buffer in a
21551 * duk_to_dynamic_buffer() call.
21552 */
21553 duk_uint_t tmp;
21554 duk_uint8_t *tmp_ptr;
21555
21556 tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
21557 src_data = (const duk_uint8_t *) tmp_ptr;
21558 src_size = DUK_HBUFFER_GET_SIZE(h_buf);
21559
21560 tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
21561 if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
21562 mode == DUK_BUF_MODE_DONTCARE) {
21563 /* Note: src_data may be NULL if input is a zero-size
21564 * dynamic buffer.
21565 */
21566 dst_data = tmp_ptr;
21567 goto skip_copy;
21568 }
21569 } else {
21570 /* Non-buffer value is first ToString() coerced, then converted
21571 * to a buffer (fixed buffer is used unless a dynamic buffer is
21572 * explicitly requested). Symbols are rejected with a TypeError.
21573 * XXX: C API could maybe allow symbol-to-buffer coercion?
21574 */
21575 src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size);
21576 }
21577
21578 dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
21579 /* dst_data may be NULL if size is zero. */
21580 duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size);
21581
21582 duk_replace(thr, idx);
21583 skip_copy:
21584
21585 if (out_size) {
21586 *out_size = src_size;
21587 }
21588 return dst_data;
21589}
21590
21591DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) {
21592 duk_tval *tv;
21593 void *res;
21594
21595 DUK_ASSERT_API_ENTRY(thr);
21596
21597 idx = duk_require_normalize_index(thr, idx);
21598 tv = DUK_GET_TVAL_POSIDX(thr, idx);
21599 DUK_ASSERT(tv != NULL);
21600
21601 switch (DUK_TVAL_GET_TAG(tv)) {
21602 case DUK_TAG_UNDEFINED:
21603 case DUK_TAG_NULL:
21604 case DUK_TAG_BOOLEAN:
21605 res = NULL;
21606 break;
21607 case DUK_TAG_POINTER:
21608 res = DUK_TVAL_GET_POINTER(tv);
21609 break;
21610 case DUK_TAG_STRING:
21611 case DUK_TAG_OBJECT:
21612 case DUK_TAG_BUFFER:
21613 /* Heap allocated: return heap pointer which is NOT useful
21614 * for the caller, except for debugging.
21615 */
21616 res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
21617 break;
21618 case DUK_TAG_LIGHTFUNC:
21619 /* Function pointers do not always cast correctly to void *
21620 * (depends on memory and segmentation model for instance),
21621 * so they coerce to NULL.
21622 */
21623 res = NULL;
21624 break;
21625#if defined(DUK_USE_FASTINT)
21626 case DUK_TAG_FASTINT:
21627#endif
21628 default:
21629 /* number */
21630 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21631 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21632 res = NULL;
21633 break;
21634 }
21635
21636 duk_push_pointer(thr, res);
21637 duk_replace(thr, idx);
21638 return res;
21639}
21640
21641DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
21642 duk_idx_t nargs;
21643 duk_uint_t flags = 0; /* shared flags for a subset of types */
21644 duk_small_uint_t lf_len;
21645 duk_hnatfunc *nf;
21646
21647 nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
21648 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
21649 nargs = (duk_idx_t) DUK_VARARGS;
21650 }
21651
21652 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21653 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
21654 DUK_HOBJECT_FLAG_CALLABLE |
21655 DUK_HOBJECT_FLAG_FASTREFS |
21656 DUK_HOBJECT_FLAG_NATFUNC |
21657 DUK_HOBJECT_FLAG_NEWENV |
21658 DUK_HOBJECT_FLAG_STRICT |
21659 DUK_HOBJECT_FLAG_NOTAIL |
21660 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
21661 (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
21662
21663 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
21664 if ((duk_idx_t) lf_len != nargs) {
21665 /* Explicit length is only needed if it differs from 'nargs'. */
21666 duk_push_int(thr, (duk_int_t) lf_len);
21667 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
21668 }
21669
21670#if defined(DUK_USE_FUNC_NAME_PROPERTY)
21671 duk_push_lightfunc_name_raw(thr, func, lf_flags);
21672 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
21673#endif
21674
21675 nf = duk_known_hnatfunc(thr, -1);
21676 nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
21677}
21678
21679DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
21680 duk_tval *tv;
21681 duk_uint_t flags = 0; /* shared flags for a subset of types */
21682 duk_small_int_t proto = 0;
21683
21684 DUK_ASSERT_API_ENTRY(thr);
21685
21686 idx = duk_require_normalize_index(thr, idx);
21687 tv = DUK_GET_TVAL_POSIDX(thr, idx);
21688 DUK_ASSERT(tv != NULL);
21689
21690 switch (DUK_TVAL_GET_TAG(tv)) {
21691#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21692 case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */
21693#endif
21694 case DUK_TAG_UNDEFINED:
21695 case DUK_TAG_NULL: {
21696 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
21697 DUK_WO_NORETURN(return;);
21698 break;
21699 }
21700 case DUK_TAG_BOOLEAN: {
21701 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21702 DUK_HOBJECT_FLAG_FASTREFS |
21703 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
21704 proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
21705 goto create_object;
21706 }
21707 case DUK_TAG_STRING: {
21708 duk_hstring *h;
21709 h = DUK_TVAL_GET_STRING(tv);
21710 DUK_ASSERT(h != NULL);
21711 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
21712 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21713 DUK_HOBJECT_FLAG_FASTREFS |
21714 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL);
21715 proto = DUK_BIDX_SYMBOL_PROTOTYPE;
21716 } else {
21717 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21718 DUK_HOBJECT_FLAG_FASTREFS |
21719 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
21720 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
21721 proto = DUK_BIDX_STRING_PROTOTYPE;
21722 }
21723 goto create_object;
21724 }
21725 case DUK_TAG_OBJECT: {
21726 /* nop */
21727 break;
21728 }
21729#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21730 case DUK_TAG_BUFFER: {
21731 /* A plain buffer object coerces to a full ArrayBuffer which
21732 * is not fully transparent behavior (ToObject() should be a
21733 * nop for an object). This behavior matches lightfuncs which
21734 * also coerce to an equivalent Function object. There are
21735 * also downsides to defining ToObject(plainBuffer) as a no-op;
21736 * for example duk_to_hobject() could result in a NULL pointer.
21737 */
21738 duk_hbuffer *h_buf;
21739
21740 h_buf = DUK_TVAL_GET_BUFFER(tv);
21741 DUK_ASSERT(h_buf != NULL);
21742 duk_hbufobj_push_uint8array_from_plain(thr, h_buf);
21743 goto replace_value;
21744 }
21745#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
21746 case DUK_TAG_POINTER: {
21747 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21748 DUK_HOBJECT_FLAG_FASTREFS |
21749 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
21750 proto = DUK_BIDX_POINTER_PROTOTYPE;
21751 goto create_object;
21752 }
21753 case DUK_TAG_LIGHTFUNC: {
21754 /* Lightfunc coerces to a Function instance with concrete
21755 * properties. Since 'length' is virtual for Duktape/C
21756 * functions, don't need to define that. The result is made
21757 * extensible to mimic what happens to strings in object
21758 * coercion:
21759 *
21760 * > Object.isExtensible(Object('foo'))
21761 * true
21762 */
21763 duk_small_uint_t lf_flags;
21764 duk_c_function func;
21765
21766 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
21767 duk__push_func_from_lightfunc(thr, func, lf_flags);
21768 goto replace_value;
21769 }
21770#if defined(DUK_USE_FASTINT)
21771 case DUK_TAG_FASTINT:
21772#endif
21773 default: {
21774 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21775 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21776 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21777 DUK_HOBJECT_FLAG_FASTREFS |
21778 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
21779 proto = DUK_BIDX_NUMBER_PROTOTYPE;
21780 goto create_object;
21781 }
21782 }
21783 DUK_ASSERT(duk_is_object(thr, idx));
21784 return;
21785
21786 create_object:
21787 (void) duk_push_object_helper(thr, flags, proto);
21788
21789 /* Note: Boolean prototype's internal value property is not writable,
21790 * but duk_xdef_prop_stridx() disregards the write protection. Boolean
21791 * instances are immutable.
21792 *
21793 * String and buffer special behaviors are already enabled which is not
21794 * ideal, but a write to the internal value is not affected by them.
21795 */
21796 duk_dup(thr, idx);
21797 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
21798
21799 replace_value:
21800 duk_replace(thr, idx);
21801 DUK_ASSERT(duk_is_object(thr, idx));
21802}
21803
21804DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) {
21805 duk_hobject *ret;
21806
21807 DUK_ASSERT_API_ENTRY(thr);
21808
21809 duk_to_object(thr, idx);
21810 ret = duk_known_hobject(thr, idx);
21811 return ret;
21812}
21813
21814/*
21815 * Type checking
21816 */
21817
21818DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) {
21819 duk_tval *tv;
21820
21821 tv = duk_get_tval_or_unused(thr, idx);
21822 DUK_ASSERT(tv != NULL);
21823 return (DUK_TVAL_GET_TAG(tv) == tag);
21824}
21825
21826DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) {
21827 duk_hobject *obj;
21828
21829 DUK_ASSERT_API_ENTRY(thr);
21830
21831 obj = duk_get_hobject(thr, idx);
21832 if (obj) {
21833 return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
21834 }
21835 return 0;
21836}
21837
21838DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
21839 DUK_ASSERT(tv != NULL);
21840
21841#if defined(DUK_USE_PACKED_TVAL)
21842 switch (DUK_TVAL_GET_TAG(tv)) {
21843 case DUK_TAG_UNUSED:
21844 return DUK_TYPE_NONE;
21845 case DUK_TAG_UNDEFINED:
21846 return DUK_TYPE_UNDEFINED;
21847 case DUK_TAG_NULL:
21848 return DUK_TYPE_NULL;
21849 case DUK_TAG_BOOLEAN:
21850 return DUK_TYPE_BOOLEAN;
21851 case DUK_TAG_STRING:
21852 return DUK_TYPE_STRING;
21853 case DUK_TAG_OBJECT:
21854 return DUK_TYPE_OBJECT;
21855 case DUK_TAG_BUFFER:
21856 return DUK_TYPE_BUFFER;
21857 case DUK_TAG_POINTER:
21858 return DUK_TYPE_POINTER;
21859 case DUK_TAG_LIGHTFUNC:
21860 return DUK_TYPE_LIGHTFUNC;
21861#if defined(DUK_USE_FASTINT)
21862 case DUK_TAG_FASTINT:
21863#endif
21864 default:
21865 /* Note: number has no explicit tag (in 8-byte representation) */
21866 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21867 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21868 return DUK_TYPE_NUMBER;
21869 }
21870#else /* DUK_USE_PACKED_TVAL */
21871 DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
21872 DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
21873 return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
21874#endif /* DUK_USE_PACKED_TVAL */
21875}
21876
21877DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) {
21878 duk_tval *tv;
21879
21880 DUK_ASSERT_API_ENTRY(thr);
21881
21882 tv = duk_get_tval_or_unused(thr, idx);
21883 DUK_ASSERT(tv != NULL);
21884
21885 return duk_get_type_tval(tv);
21886}
21887
21888#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
21889DUK_LOCAL const char * const duk__type_names[] = {
21890 "none",
21891 "undefined",
21892 "null",
21893 "boolean",
21894 "number",
21895 "string",
21896 "object",
21897 "buffer",
21898 "pointer",
21899 "lightfunc"
21900};
21901
21902DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) {
21903 duk_int_t type_tag;
21904
21905 DUK_ASSERT_API_ENTRY(thr);
21906
21907 type_tag = duk_get_type(thr, idx);
21908 DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
21909 DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
21910
21911 return duk__type_names[type_tag];
21912}
21913#endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */
21914
21915DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) {
21916 duk_tval *tv;
21917 duk_hobject *obj;
21918
21919 DUK_ASSERT_API_ENTRY(thr);
21920
21921 tv = duk_get_tval_or_unused(thr, idx);
21922 DUK_ASSERT(tv != NULL);
21923
21924 switch (DUK_TVAL_GET_TAG(tv)) {
21925 case DUK_TAG_OBJECT:
21926 obj = DUK_TVAL_GET_OBJECT(tv);
21927 DUK_ASSERT(obj != NULL);
21928 return DUK_HOBJECT_GET_CLASS_NUMBER(obj);
21929 case DUK_TAG_BUFFER:
21930 /* Buffers behave like Uint8Array objects. */
21931 return DUK_HOBJECT_CLASS_UINT8ARRAY;
21932 case DUK_TAG_LIGHTFUNC:
21933 /* Lightfuncs behave like Function objects. */
21934 return DUK_HOBJECT_CLASS_FUNCTION;
21935 default:
21936 /* Primitive or UNUSED, no class number. */
21937 return DUK_HOBJECT_CLASS_NONE;
21938 }
21939}
21940
21941DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) {
21942 DUK_ASSERT_API_ENTRY(thr);
21943
21944 return (duk_get_type(thr, idx) == type) ? 1 : 0;
21945}
21946
21947DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
21948 DUK_ASSERT(tv != NULL);
21949
21950#if defined(DUK_USE_PACKED_TVAL)
21951 switch (DUK_TVAL_GET_TAG(tv)) {
21952 case DUK_TAG_UNUSED:
21953 return DUK_TYPE_MASK_NONE;
21954 case DUK_TAG_UNDEFINED:
21955 return DUK_TYPE_MASK_UNDEFINED;
21956 case DUK_TAG_NULL:
21957 return DUK_TYPE_MASK_NULL;
21958 case DUK_TAG_BOOLEAN:
21959 return DUK_TYPE_MASK_BOOLEAN;
21960 case DUK_TAG_STRING:
21961 return DUK_TYPE_MASK_STRING;
21962 case DUK_TAG_OBJECT:
21963 return DUK_TYPE_MASK_OBJECT;
21964 case DUK_TAG_BUFFER:
21965 return DUK_TYPE_MASK_BUFFER;
21966 case DUK_TAG_POINTER:
21967 return DUK_TYPE_MASK_POINTER;
21968 case DUK_TAG_LIGHTFUNC:
21969 return DUK_TYPE_MASK_LIGHTFUNC;
21970#if defined(DUK_USE_FASTINT)
21971 case DUK_TAG_FASTINT:
21972#endif
21973 default:
21974 /* Note: number has no explicit tag (in 8-byte representation) */
21975 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21976 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21977 return DUK_TYPE_MASK_NUMBER;
21978 }
21979#else /* DUK_USE_PACKED_TVAL */
21980 DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
21981 DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
21982 return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
21983#endif /* DUK_USE_PACKED_TVAL */
21984}
21985
21986DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) {
21987 duk_tval *tv;
21988
21989 DUK_ASSERT_API_ENTRY(thr);
21990
21991 tv = duk_get_tval_or_unused(thr, idx);
21992 DUK_ASSERT(tv != NULL);
21993
21994 return duk_get_type_mask_tval(tv);
21995}
21996
21997DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) {
21998 DUK_ASSERT_API_ENTRY(thr);
21999
22000 if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) {
22001 return 1;
22002 }
22003 if (mask & DUK_TYPE_MASK_THROW) {
22004 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
22005 DUK_WO_NORETURN(return 0;);
22006 }
22007 return 0;
22008}
22009
22010DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) {
22011 DUK_ASSERT_API_ENTRY(thr);
22012 return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED);
22013}
22014
22015DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) {
22016 DUK_ASSERT_API_ENTRY(thr);
22017 return duk__tag_check(thr, idx, DUK_TAG_NULL);
22018}
22019
22020DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) {
22021 DUK_ASSERT_API_ENTRY(thr);
22022 return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN);
22023}
22024
22025DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) {
22026 duk_tval *tv;
22027
22028 DUK_ASSERT_API_ENTRY(thr);
22029
22030 /*
22031 * Number is special because it doesn't have a specific
22032 * tag in the 8-byte representation.
22033 */
22034
22035 /* XXX: shorter version for unpacked representation? */
22036
22037 tv = duk_get_tval_or_unused(thr, idx);
22038 DUK_ASSERT(tv != NULL);
22039 return DUK_TVAL_IS_NUMBER(tv);
22040}
22041
22042DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) {
22043 /* XXX: This will now return false for non-numbers, even though they would
22044 * coerce to NaN (as a general rule). In particular, duk_get_number()
22045 * returns a NaN for non-numbers, so should this function also return
22046 * true for non-numbers?
22047 */
22048
22049 duk_tval *tv;
22050
22051 DUK_ASSERT_API_ENTRY(thr);
22052
22053 tv = duk_get_tval_or_unused(thr, idx);
22054 DUK_ASSERT(tv != NULL);
22055
22056 /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
22057 if (!DUK_TVAL_IS_NUMBER(tv)) {
22058 return 0;
22059 }
22060 return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
22061}
22062
22063DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) {
22064 DUK_ASSERT_API_ENTRY(thr);
22065 return duk__tag_check(thr, idx, DUK_TAG_STRING);
22066}
22067
22068DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
22069 DUK_ASSERT_API_ENTRY(thr);
22070 return duk_get_hstring_notsymbol(thr, idx) != NULL;
22071}
22072
22073DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) {
22074 DUK_ASSERT_API_ENTRY(thr);
22075 return duk__tag_check(thr, idx, DUK_TAG_OBJECT);
22076}
22077
22078DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) {
22079 DUK_ASSERT_API_ENTRY(thr);
22080 return duk__tag_check(thr, idx, DUK_TAG_BUFFER);
22081}
22082
22083#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22084DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
22085 duk_tval *tv;
22086
22087 DUK_ASSERT_API_ENTRY(thr);
22088
22089 tv = duk_get_tval_or_unused(thr, idx);
22090 DUK_ASSERT(tv != NULL);
22091 if (DUK_TVAL_IS_BUFFER(tv)) {
22092 return 1;
22093 } else if (DUK_TVAL_IS_OBJECT(tv)) {
22094 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
22095 DUK_ASSERT(h != NULL);
22096 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
22097 return 1;
22098 }
22099 }
22100 return 0;
22101}
22102#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
22103DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
22104 DUK_ASSERT_API_ENTRY(thr);
22105
22106 return duk_is_buffer(thr, idx);
22107}
22108
22109#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
22110
22111DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) {
22112 DUK_ASSERT_API_ENTRY(thr);
22113 return duk__tag_check(thr, idx, DUK_TAG_POINTER);
22114}
22115
22116DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) {
22117 DUK_ASSERT_API_ENTRY(thr);
22118 return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC);
22119}
22120
22121DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) {
22122 duk_hstring *h;
22123
22124 DUK_ASSERT_API_ENTRY(thr);
22125 h = duk_get_hstring(thr, idx);
22126 /* Use DUK_LIKELY() here because caller may be more likely to type
22127 * check an expected symbol than not.
22128 */
22129 if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) {
22130 return 1;
22131 }
22132 return 0;
22133}
22134
22135/* IsArray(), returns true for Array instance or Proxy of Array instance. */
22136DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) {
22137 duk_tval *tv;
22138
22139 DUK_ASSERT_API_ENTRY(thr);
22140
22141 tv = duk_get_tval(thr, idx);
22142 if (tv) {
22143 return duk_js_isarray(tv);
22144 }
22145 return 0;
22146}
22147
22148DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) {
22149 duk_tval *tv;
22150
22151 DUK_ASSERT_API_ENTRY(thr);
22152
22153 tv = duk_get_tval_or_unused(thr, idx);
22154 if (DUK_TVAL_IS_OBJECT(tv)) {
22155 duk_hobject *h;
22156 h = DUK_TVAL_GET_OBJECT(tv);
22157 DUK_ASSERT(h != NULL);
22158 return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
22159 }
22160 if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
22161 return 1;
22162 }
22163 return 0;
22164}
22165
22166DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) {
22167 DUK_ASSERT_API_ENTRY(thr);
22168
22169 DUK_UNREF(thr);
22170
22171 if (DUK_TVAL_IS_OBJECT(tv)) {
22172 duk_hobject *h;
22173 h = DUK_TVAL_GET_OBJECT(tv);
22174 DUK_ASSERT(h != NULL);
22175 return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
22176 }
22177 if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
22178 return 1;
22179 }
22180 return 0;
22181}
22182
22183DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) {
22184 duk_tval *tv;
22185
22186 DUK_ASSERT_API_ENTRY(thr);
22187
22188 tv = duk_get_tval_or_unused(thr, idx);
22189 if (DUK_TVAL_IS_OBJECT(tv)) {
22190 duk_hobject *h;
22191 h = DUK_TVAL_GET_OBJECT(tv);
22192 DUK_ASSERT(h != NULL);
22193 return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0;
22194 }
22195 if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
22196 return 1;
22197 }
22198 return 0;
22199}
22200
22201DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) {
22202 DUK_ASSERT_API_ENTRY(thr);
22203 return duk__obj_flag_any_default_false(thr,
22204 idx,
22205 DUK_HOBJECT_FLAG_NATFUNC);
22206}
22207
22208DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) {
22209 DUK_ASSERT_API_ENTRY(thr);
22210 return duk__obj_flag_any_default_false(thr,
22211 idx,
22212 DUK_HOBJECT_FLAG_COMPFUNC);
22213}
22214
22215DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) {
22216 DUK_ASSERT_API_ENTRY(thr);
22217 return duk__obj_flag_any_default_false(thr,
22218 idx,
22219 DUK_HOBJECT_FLAG_BOUNDFUNC);
22220}
22221
22222DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) {
22223 duk_hobject *obj;
22224
22225 DUK_ASSERT_API_ENTRY(thr);
22226
22227 obj = duk_get_hobject(thr, idx);
22228 if (obj) {
22229 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0);
22230 }
22231 return 0;
22232}
22233
22234DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) {
22235 duk_tval *tv;
22236
22237 DUK_ASSERT_API_ENTRY(thr);
22238
22239 tv = duk_get_tval_or_unused(thr, idx);
22240 DUK_ASSERT(tv != NULL);
22241 if (DUK_TVAL_IS_BUFFER(tv)) {
22242 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
22243 DUK_ASSERT(h != NULL);
22244 return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
22245 }
22246 return 0;
22247}
22248
22249DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) {
22250 duk_tval *tv;
22251
22252 DUK_ASSERT_API_ENTRY(thr);
22253
22254 tv = duk_get_tval_or_unused(thr, idx);
22255 DUK_ASSERT(tv != NULL);
22256 if (DUK_TVAL_IS_BUFFER(tv)) {
22257 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
22258 DUK_ASSERT(h != NULL);
22259 return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
22260 }
22261 return 0;
22262}
22263
22264DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) {
22265 duk_tval *tv;
22266
22267 DUK_ASSERT_API_ENTRY(thr);
22268
22269 tv = duk_get_tval_or_unused(thr, idx);
22270 DUK_ASSERT(tv != NULL);
22271 if (DUK_TVAL_IS_BUFFER(tv)) {
22272 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
22273 DUK_ASSERT(h != NULL);
22274 return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
22275 }
22276 return 0;
22277}
22278
22279DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) {
22280 duk_hobject *h;
22281 duk_uint_t sanity;
22282
22283 DUK_ASSERT_API_ENTRY(thr);
22284
22285 h = duk_get_hobject(thr, idx);
22286
22287 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
22288 do {
22289 if (!h) {
22290 return DUK_ERR_NONE;
22291 }
22292
22293 /* XXX: something more convenient? */
22294
22295 if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
22296 return DUK_ERR_EVAL_ERROR;
22297 }
22298 if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
22299 return DUK_ERR_RANGE_ERROR;
22300 }
22301 if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
22302 return DUK_ERR_REFERENCE_ERROR;
22303 }
22304 if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
22305 return DUK_ERR_SYNTAX_ERROR;
22306 }
22307 if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
22308 return DUK_ERR_TYPE_ERROR;
22309 }
22310 if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
22311 return DUK_ERR_URI_ERROR;
22312 }
22313 if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
22314 return DUK_ERR_ERROR;
22315 }
22316
22317 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
22318 } while (--sanity > 0);
22319
22320 return DUK_ERR_NONE;
22321}
22322
22323/*
22324 * Pushers
22325 */
22326
22327DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) {
22328 duk_tval *tv_slot;
22329
22330 DUK_ASSERT_API_ENTRY(thr);
22331 DUK_ASSERT(tv != NULL);
22332
22333 DUK__CHECK_SPACE();
22334 tv_slot = thr->valstack_top++;
22335 DUK_TVAL_SET_TVAL(tv_slot, tv);
22336 DUK_TVAL_INCREF(thr, tv); /* no side effects */
22337}
22338
22339DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) {
22340 DUK_ASSERT_API_ENTRY(thr);
22341
22342 DUK__CHECK_SPACE();
22343
22344 /* Because value stack init policy is 'undefined above top',
22345 * we don't need to write, just assert.
22346 */
22347 thr->valstack_top++;
22348 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
22349}
22350
22351DUK_EXTERNAL void duk_push_null(duk_hthread *thr) {
22352 duk_tval *tv_slot;
22353
22354 DUK_ASSERT_API_ENTRY(thr);
22355 DUK__CHECK_SPACE();
22356 tv_slot = thr->valstack_top++;
22357 DUK_TVAL_SET_NULL(tv_slot);
22358}
22359
22360DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) {
22361 duk_tval *tv_slot;
22362 duk_small_int_t b;
22363
22364 DUK_ASSERT_API_ENTRY(thr);
22365 DUK__CHECK_SPACE();
22366 b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
22367 tv_slot = thr->valstack_top++;
22368 DUK_TVAL_SET_BOOLEAN(tv_slot, b);
22369}
22370
22371DUK_EXTERNAL void duk_push_true(duk_hthread *thr) {
22372 duk_tval *tv_slot;
22373
22374 DUK_ASSERT_API_ENTRY(thr);
22375 DUK__CHECK_SPACE();
22376 tv_slot = thr->valstack_top++;
22377 DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
22378}
22379
22380DUK_EXTERNAL void duk_push_false(duk_hthread *thr) {
22381 duk_tval *tv_slot;
22382
22383 DUK_ASSERT_API_ENTRY(thr);
22384 DUK__CHECK_SPACE();
22385 tv_slot = thr->valstack_top++;
22386 DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
22387}
22388
22389/* normalize NaN which may not match our canonical internal NaN */
22390DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) {
22391 duk_tval *tv_slot;
22392 duk_double_union du;
22393
22394 DUK_ASSERT_API_ENTRY(thr);
22395 DUK__CHECK_SPACE();
22396 du.d = val;
22397 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
22398 tv_slot = thr->valstack_top++;
22399 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
22400}
22401
22402DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) {
22403#if defined(DUK_USE_FASTINT)
22404 duk_tval *tv_slot;
22405
22406 DUK_ASSERT_API_ENTRY(thr);
22407 DUK__CHECK_SPACE();
22408 tv_slot = thr->valstack_top++;
22409#if DUK_INT_MAX <= 0x7fffffffL
22410 DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val);
22411#else
22412 if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
22413 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
22414 } else {
22415 duk_double_t = (duk_double_t) val;
22416 DUK_TVAL_SET_NUMBER(tv_slot, d);
22417 }
22418#endif
22419#else /* DUK_USE_FASTINT */
22420 duk_tval *tv_slot;
22421 duk_double_t d;
22422
22423 DUK_ASSERT_API_ENTRY(thr);
22424 DUK__CHECK_SPACE();
22425 d = (duk_double_t) val;
22426 tv_slot = thr->valstack_top++;
22427 DUK_TVAL_SET_NUMBER(tv_slot, d);
22428#endif /* DUK_USE_FASTINT */
22429}
22430
22431DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) {
22432#if defined(DUK_USE_FASTINT)
22433 duk_tval *tv_slot;
22434
22435 DUK_ASSERT_API_ENTRY(thr);
22436 DUK__CHECK_SPACE();
22437 tv_slot = thr->valstack_top++;
22438#if DUK_UINT_MAX <= 0xffffffffUL
22439 DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val);
22440#else
22441 if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
22442 /* XXX: take advantage of val being unsigned, no need to mask */
22443 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
22444 } else {
22445 duk_double_t = (duk_double_t) val;
22446 DUK_TVAL_SET_NUMBER(tv_slot, d);
22447 }
22448#endif
22449#else /* DUK_USE_FASTINT */
22450 duk_tval *tv_slot;
22451 duk_double_t d;
22452
22453 DUK_ASSERT_API_ENTRY(thr);
22454 DUK__CHECK_SPACE();
22455 d = (duk_double_t) val;
22456 tv_slot = thr->valstack_top++;
22457 DUK_TVAL_SET_NUMBER(tv_slot, d);
22458#endif /* DUK_USE_FASTINT */
22459}
22460
22461DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) {
22462 duk_tval *tv_slot;
22463 duk_double_union du;
22464
22465 DUK_ASSERT_API_ENTRY(thr);
22466 DUK__CHECK_SPACE();
22467 DUK_DBLUNION_SET_NAN(&du);
22468 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
22469 tv_slot = thr->valstack_top++;
22470 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
22471}
22472
22473DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) {
22474 duk_hstring *h;
22475 duk_tval *tv_slot;
22476
22477 DUK_ASSERT_API_ENTRY(thr);
22478
22479 /* Check stack before interning (avoid hanging temp). */
22480 DUK__CHECK_SPACE();
22481
22482 /* NULL with zero length represents an empty string; NULL with higher
22483 * length is also now treated like an empty string although it is
22484 * a bit dubious. This is unlike duk_push_string() which pushes a
22485 * 'null' if the input string is a NULL.
22486 */
22487 if (DUK_UNLIKELY(str == NULL)) {
22488 len = 0U;
22489 }
22490
22491 /* Check for maximum string length. */
22492 if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
22493 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
22494 DUK_WO_NORETURN(return NULL;);
22495 }
22496
22497 h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
22498 DUK_ASSERT(h != NULL);
22499
22500 tv_slot = thr->valstack_top++;
22501 DUK_TVAL_SET_STRING(tv_slot, h);
22502 DUK_HSTRING_INCREF(thr, h); /* no side effects */
22503
22504 return (const char *) DUK_HSTRING_GET_DATA(h);
22505}
22506
22507DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
22508 DUK_ASSERT_API_ENTRY(thr);
22509
22510 if (str) {
22511 return duk_push_lstring(thr, str, DUK_STRLEN(str));
22512 } else {
22513 duk_push_null(thr);
22514 return NULL;
22515 }
22516}
22517
22518#if !defined(DUK_USE_PREFER_SIZE)
22519#if defined(DUK_USE_LITCACHE_SIZE)
22520DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
22521 duk_hstring *h;
22522 duk_tval *tv_slot;
22523
22524 DUK_ASSERT_API_ENTRY(thr);
22525 DUK_ASSERT(str != NULL);
22526 DUK_ASSERT(str[len] == (char) 0);
22527
22528 /* Check for maximum string length. */
22529 if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
22530 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
22531 DUK_WO_NORETURN(return NULL;);
22532 }
22533
22534 h = duk_heap_strtable_intern_literal_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
22535 DUK_ASSERT(h != NULL);
22536
22537 tv_slot = thr->valstack_top++;
22538 DUK_TVAL_SET_STRING(tv_slot, h);
22539 DUK_HSTRING_INCREF(thr, h); /* no side effects */
22540
22541 return (const char *) DUK_HSTRING_GET_DATA(h);
22542}
22543#else /* DUK_USE_LITCACHE_SIZE */
22544DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
22545 DUK_ASSERT_API_ENTRY(thr);
22546 DUK_ASSERT(str != NULL);
22547 DUK_ASSERT(str[len] == (char) 0);
22548
22549 return duk_push_lstring(thr, str, len);
22550}
22551#endif /* DUK_USE_LITCACHE_SIZE */
22552#endif /* !DUK_USE_PREFER_SIZE */
22553
22554DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
22555 duk_tval *tv_slot;
22556
22557 DUK_ASSERT_API_ENTRY(thr);
22558 DUK__CHECK_SPACE();
22559 tv_slot = thr->valstack_top++;
22560 DUK_TVAL_SET_POINTER(tv_slot, val);
22561}
22562
22563DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) {
22564 duk_hstring *h_tmp;
22565
22566 DUK_ASSERT_API_ENTRY(thr);
22567
22568 /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
22569 duk_push_uint(thr, (duk_uint_t) i);
22570 h_tmp = duk_to_hstring_m1(thr);
22571 DUK_ASSERT(h_tmp != NULL);
22572 return h_tmp;
22573}
22574
22575DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) {
22576 duk_tval *tv_slot;
22577
22578 DUK__CHECK_SPACE();
22579
22580 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
22581 tv_slot = thr->valstack_top++;
22582
22583 if (DUK_UNLIKELY(thr->callstack_curr == NULL)) {
22584 if (check_object_coercible) {
22585 goto type_error;
22586 }
22587 /* 'undefined' already on stack top */
22588 } else {
22589 duk_tval *tv;
22590
22591 /* 'this' binding is just before current activation's bottom */
22592 DUK_ASSERT(thr->valstack_bottom > thr->valstack);
22593 tv = thr->valstack_bottom - 1;
22594 if (check_object_coercible &&
22595 (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
22596 /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
22597 goto type_error;
22598 }
22599
22600 DUK_TVAL_SET_TVAL(tv_slot, tv);
22601 DUK_TVAL_INCREF(thr, tv);
22602 }
22603 return;
22604
22605 type_error:
22606 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
22607 DUK_WO_NORETURN(return;);
22608}
22609
22610DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
22611 DUK_ASSERT_API_ENTRY(thr);
22612
22613 duk__push_this_helper(thr, 0 /*check_object_coercible*/);
22614}
22615
22616DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) {
22617 DUK_ASSERT_API_ENTRY(thr);
22618
22619 duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22620}
22621
22622DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) {
22623 duk_hobject *h;
22624
22625 DUK_ASSERT_API_ENTRY(thr);
22626
22627 duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22628 h = duk_to_hobject(thr, -1);
22629 DUK_ASSERT(h != NULL);
22630 return h;
22631}
22632
22633DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) {
22634 DUK_ASSERT_API_ENTRY(thr);
22635
22636 duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22637 return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */
22638}
22639
22640DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
22641 DUK_ASSERT_API_ENTRY(thr);
22642
22643 DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
22644 DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */
22645 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
22646 DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
22647
22648 return thr->valstack_bottom - 1;
22649}
22650
22651DUK_EXTERNAL void duk_push_new_target(duk_hthread *thr) {
22652 duk_activation *act;
22653
22654 DUK_ASSERT_API_ENTRY(thr);
22655
22656 /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation
22657 * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
22658 *
22659 * No newTarget support now, so as a first approximation
22660 * use the resolved (non-bound) target function.
22661 *
22662 * Check CONSTRUCT flag from current function, or if running
22663 * direct eval, from a non-direct-eval parent (with possibly
22664 * more than one nested direct eval). An alternative to this
22665 * would be to store [[NewTarget]] as a hidden symbol of the
22666 * lexical scope, and then just look up that variable.
22667 *
22668 * Calls from the application will either be for an empty
22669 * call stack, or a Duktape/C function as the top activation.
22670 */
22671
22672 act = thr->callstack_curr;
22673 for (;;) {
22674 if (act == NULL) {
22675 break;
22676 }
22677
22678 if (act->flags & DUK_ACT_FLAG_CONSTRUCT) {
22679 duk_push_tval(thr, &act->tv_func);
22680 return;
22681 } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
22682 act = act->parent;
22683 } else {
22684 break;
22685 }
22686 }
22687
22688 duk_push_undefined(thr);
22689}
22690
22691DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
22692 duk_activation *act;
22693
22694 DUK_ASSERT_API_ENTRY(thr);
22695
22696 act = thr->callstack_curr;
22697 if (act != NULL) {
22698 duk_push_tval(thr, &act->tv_func);
22699 } else {
22700 duk_push_undefined(thr);
22701 }
22702}
22703
22704DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) {
22705 DUK_ASSERT_API_ENTRY(thr);
22706
22707 if (thr->heap->curr_thread) {
22708 duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread);
22709 } else {
22710 duk_push_undefined(thr);
22711 }
22712}
22713
22714DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) {
22715 DUK_ASSERT_API_ENTRY(thr);
22716
22717 duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
22718}
22719
22720/* XXX: size optimize */
22721DUK_LOCAL void duk__push_stash(duk_hthread *thr) {
22722 if (!duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) {
22723 DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
22724 duk_pop_unsafe(thr);
22725 duk_push_bare_object(thr);
22726 duk_dup_top(thr);
22727 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
22728 }
22729 duk_remove_m2(thr);
22730}
22731
22732DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) {
22733 duk_heap *heap;
22734 DUK_ASSERT_API_ENTRY(thr);
22735 heap = thr->heap;
22736 DUK_ASSERT(heap->heap_object != NULL);
22737 duk_push_hobject(thr, heap->heap_object);
22738 duk__push_stash(thr);
22739}
22740
22741DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) {
22742 DUK_ASSERT_API_ENTRY(thr);
22743 duk_push_global_object(thr);
22744 duk__push_stash(thr);
22745}
22746
22747DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) {
22748 DUK_ASSERT_API_ENTRY(thr);
22749 if (DUK_UNLIKELY(target_thr == NULL)) {
22750 DUK_ERROR_TYPE_INVALID_ARGS(thr);
22751 DUK_WO_NORETURN(return;);
22752 }
22753 duk_push_hobject(thr, (duk_hobject *) target_thr);
22754 duk__push_stash(thr);
22755}
22756
22757/* XXX: duk_ssize_t would be useful here */
22758DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
22759 duk_int_t len;
22760
22761 DUK_CTX_ASSERT_VALID(thr);
22762 DUK_UNREF(thr);
22763
22764 /* NUL terminator handling doesn't matter here */
22765 len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
22766 if (len < (duk_int_t) sz) {
22767 /* Return value of 'sz' or more indicates output was (potentially)
22768 * truncated.
22769 */
22770 return (duk_int_t) len;
22771 }
22772 return -1;
22773}
22774
22775DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) {
22776 duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
22777 duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
22778 duk_bool_t pushed_buf = 0;
22779 void *buf;
22780 duk_int_t len; /* XXX: duk_ssize_t */
22781 const char *res;
22782
22783 DUK_ASSERT_API_ENTRY(thr);
22784
22785 /* special handling of fmt==NULL */
22786 if (!fmt) {
22787 duk_hstring *h_str;
22788 duk_push_hstring_empty(thr);
22789 h_str = duk_known_hstring(thr, -1);
22790 return (const char *) DUK_HSTRING_GET_DATA(h_str);
22791 }
22792
22793 /* initial estimate based on format string */
22794 sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */
22795 if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
22796 sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
22797 }
22798 DUK_ASSERT(sz > 0);
22799
22800 /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
22801 * This works 99% of the time which is quite nice.
22802 */
22803 for (;;) {
22804 va_list ap_copy; /* copied so that 'ap' can be reused */
22805
22806 if (sz <= sizeof(stack_buf)) {
22807 buf = stack_buf;
22808 } else if (!pushed_buf) {
22809 pushed_buf = 1;
22810 buf = duk_push_dynamic_buffer(thr, sz);
22811 } else {
22812 buf = duk_resize_buffer(thr, -1, sz);
22813 }
22814 DUK_ASSERT(buf != NULL);
22815
22816 DUK_VA_COPY(ap_copy, ap);
22817 len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy);
22818 va_end(ap_copy);
22819 if (len >= 0) {
22820 break;
22821 }
22822
22823 /* failed, resize and try again */
22824 sz = sz * 2;
22825 if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) {
22826 DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
22827 DUK_WO_NORETURN(return NULL;);
22828 }
22829 }
22830
22831 /* Cannot use duk_buffer_to_string() on the buffer because it is
22832 * usually larger than 'len'; 'buf' is also usually a stack buffer.
22833 */
22834 res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
22835 if (pushed_buf) {
22836 duk_remove_m2(thr);
22837 }
22838 return res;
22839}
22840
22841DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) {
22842 va_list ap;
22843 const char *ret;
22844
22845 DUK_ASSERT_API_ENTRY(thr);
22846
22847 /* allow fmt==NULL */
22848 va_start(ap, fmt);
22849 ret = duk_push_vsprintf(thr, fmt, ap);
22850 va_end(ap);
22851
22852 return ret;
22853}
22854
22855DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
22856 duk_tval *tv_slot;
22857 duk_hobject *h;
22858
22859 DUK_ASSERT_API_ENTRY(thr);
22860 DUK_ASSERT(prototype_bidx == -1 ||
22861 (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
22862
22863 DUK__CHECK_SPACE();
22864
22865 h = duk_hobject_alloc(thr, hobject_flags_and_class);
22866 DUK_ASSERT(h != NULL);
22867
22868 DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
22869
22870 tv_slot = thr->valstack_top;
22871 DUK_TVAL_SET_OBJECT(tv_slot, h);
22872 DUK_HOBJECT_INCREF(thr, h); /* no side effects */
22873 thr->valstack_top++;
22874
22875 /* object is now reachable */
22876
22877 if (prototype_bidx >= 0) {
22878 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]);
22879 } else {
22880 DUK_ASSERT(prototype_bidx == -1);
22881 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
22882 }
22883
22884 return h;
22885}
22886
22887DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
22888 duk_hobject *h;
22889
22890 DUK_ASSERT_API_ENTRY(thr);
22891
22892 h = duk_push_object_helper(thr, hobject_flags_and_class, -1);
22893 DUK_ASSERT(h != NULL);
22894 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto);
22895 return h;
22896}
22897
22898DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) {
22899 DUK_ASSERT_API_ENTRY(thr);
22900
22901 (void) duk_push_object_helper(thr,
22902 DUK_HOBJECT_FLAG_EXTENSIBLE |
22903 DUK_HOBJECT_FLAG_FASTREFS |
22904 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
22905 DUK_BIDX_OBJECT_PROTOTYPE);
22906 return duk_get_top_index_unsafe(thr);
22907}
22908
22909DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) {
22910 duk_uint_t flags;
22911 duk_harray *obj;
22912 duk_idx_t ret;
22913 duk_tval *tv_slot;
22914
22915 DUK_ASSERT_API_ENTRY(thr);
22916
22917 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22918 DUK_HOBJECT_FLAG_FASTREFS |
22919 DUK_HOBJECT_FLAG_ARRAY_PART |
22920 DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
22921 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
22922
22923 obj = duk_harray_alloc(thr, flags);
22924 DUK_ASSERT(obj != NULL);
22925
22926 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
22927
22928 tv_slot = thr->valstack_top;
22929 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22930 DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */
22931 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22932 thr->valstack_top++;
22933
22934 DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */
22935 return ret;
22936}
22937
22938DUK_EXTERNAL duk_idx_t duk_push_bare_array(duk_hthread *thr) {
22939 duk_uint_t flags;
22940 duk_harray *obj;
22941 duk_idx_t ret;
22942 duk_tval *tv_slot;
22943
22944 DUK_ASSERT_API_ENTRY(thr);
22945
22946 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22947 DUK_HOBJECT_FLAG_FASTREFS |
22948 DUK_HOBJECT_FLAG_ARRAY_PART |
22949 DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
22950 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
22951
22952 obj = duk_harray_alloc(thr, flags);
22953 DUK_ASSERT(obj != NULL);
22954
22955 tv_slot = thr->valstack_top;
22956 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22957 DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */
22958 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22959 thr->valstack_top++;
22960
22961 DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */
22962 return ret;
22963}
22964
22965DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) {
22966 /* XXX: API call could do this directly, cast to void in API macro. */
22967 duk_harray *a;
22968
22969 DUK_ASSERT_API_ENTRY(thr);
22970
22971 (void) duk_push_array(thr);
22972 DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
22973 a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
22974 DUK_ASSERT(a != NULL);
22975 return a;
22976}
22977
22978/* Push a duk_harray with preallocated size (.length also set to match size).
22979 * Caller may then populate array part of the duk_harray directly.
22980 */
22981DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) {
22982 duk_harray *a;
22983
22984 DUK_ASSERT_API_ENTRY(thr);
22985
22986 a = duk_push_harray(thr);
22987
22988 duk_hobject_realloc_props(thr,
22989 (duk_hobject *) a,
22990 0,
22991 size,
22992 0,
22993 0);
22994 a->length = size;
22995 return a;
22996}
22997
22998DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) {
22999 duk_harray *a;
23000
23001 DUK_ASSERT_API_ENTRY(thr);
23002
23003 a = duk_push_harray_with_size(thr, size);
23004 DUK_ASSERT(a != NULL);
23005 return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
23006}
23007
23008DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
23009 duk_hthread *obj;
23010 duk_idx_t ret;
23011 duk_tval *tv_slot;
23012
23013 DUK_ASSERT_API_ENTRY(thr);
23014
23015 DUK__CHECK_SPACE();
23016
23017 obj = duk_hthread_alloc(thr,
23018 DUK_HOBJECT_FLAG_EXTENSIBLE |
23019 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
23020 DUK_ASSERT(obj != NULL);
23021 obj->state = DUK_HTHREAD_STATE_INACTIVE;
23022#if defined(DUK_USE_ROM_STRINGS)
23023 /* Nothing to initialize, strs[] is in ROM. */
23024#else
23025#if defined(DUK_USE_HEAPPTR16)
23026 obj->strs16 = thr->strs16;
23027#else
23028 obj->strs = thr->strs;
23029#endif
23030#endif
23031 DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
23032
23033 /* make the new thread reachable */
23034 tv_slot = thr->valstack_top;
23035 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
23036 DUK_HTHREAD_INCREF(thr, obj);
23037 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
23038 thr->valstack_top++;
23039
23040 /* important to do this *after* pushing, to make the thread reachable for gc */
23041 if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) {
23042 DUK_ERROR_ALLOC_FAILED(thr);
23043 DUK_WO_NORETURN(return 0;);
23044 }
23045
23046 /* initialize built-ins - either by copying or creating new ones */
23047 if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
23048 duk_hthread_create_builtin_objects(obj);
23049 } else {
23050 duk_hthread_copy_builtin_objects(thr, obj);
23051 }
23052
23053 /* default prototype */
23054 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
23055
23056 /* Initial stack size satisfies the stack slack constraints so there
23057 * is no need to require stack here.
23058 */
23059 DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
23060 DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
23061
23062 return ret;
23063}
23064
23065DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
23066 duk_hcompfunc *obj;
23067 duk_tval *tv_slot;
23068
23069 DUK_ASSERT_API_ENTRY(thr);
23070
23071 DUK__CHECK_SPACE();
23072
23073 /* Template functions are not strictly constructable (they don't
23074 * have a "prototype" property for instance), so leave the
23075 * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
23076 */
23077
23078 obj = duk_hcompfunc_alloc(thr,
23079 DUK_HOBJECT_FLAG_EXTENSIBLE |
23080 DUK_HOBJECT_FLAG_CALLABLE |
23081 DUK_HOBJECT_FLAG_COMPFUNC |
23082 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
23083 if (DUK_UNLIKELY(obj == NULL)) {
23084 DUK_ERROR_ALLOC_FAILED(thr);
23085 DUK_WO_NORETURN(return NULL;);
23086 }
23087
23088 DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
23089
23090 tv_slot = thr->valstack_top;
23091 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
23092 DUK_HOBJECT_INCREF(thr, obj);
23093 thr->valstack_top++;
23094
23095 /* default prototype */
23096 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
23097 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
23098
23099 return obj;
23100}
23101
23102DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
23103 duk_hboundfunc *obj;
23104 duk_tval *tv_slot;
23105
23106 DUK_ASSERT_API_ENTRY(thr);
23107
23108 DUK__CHECK_SPACE();
23109 obj = duk_hboundfunc_alloc(thr->heap,
23110 DUK_HOBJECT_FLAG_EXTENSIBLE |
23111 DUK_HOBJECT_FLAG_BOUNDFUNC |
23112 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
23113 DUK_HOBJECT_FLAG_CALLABLE |
23114 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
23115 if (!obj) {
23116 DUK_ERROR_ALLOC_FAILED(thr);
23117 DUK_WO_NORETURN(return NULL;);
23118 }
23119
23120 tv_slot = thr->valstack_top++;
23121 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
23122 DUK_HOBJECT_INCREF(thr, obj);
23123
23124 /* Prototype is left as NULL because the caller always sets it (and
23125 * it depends on the target function).
23126 */
23127 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
23128
23129 return obj;
23130}
23131
23132DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) {
23133 duk_hnatfunc *obj;
23134 duk_idx_t ret;
23135 duk_tval *tv_slot;
23136 duk_int16_t func_nargs;
23137
23138 DUK_CTX_ASSERT_VALID(thr);
23139
23140 DUK__CHECK_SPACE();
23141
23142 if (DUK_UNLIKELY(func == NULL)) {
23143 goto api_error;
23144 }
23145 if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) {
23146 func_nargs = (duk_int16_t) nargs;
23147 } else if (nargs == DUK_VARARGS) {
23148 func_nargs = DUK_HNATFUNC_NARGS_VARARGS;
23149 } else {
23150 goto api_error;
23151 }
23152
23153 obj = duk_hnatfunc_alloc(thr, flags);
23154 DUK_ASSERT(obj != NULL);
23155
23156 obj->func = func;
23157 obj->nargs = func_nargs;
23158
23159 DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
23160 (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
23161
23162 tv_slot = thr->valstack_top;
23163 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
23164 DUK_HOBJECT_INCREF(thr, obj);
23165 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
23166 thr->valstack_top++;
23167
23168 DUK_ASSERT_BIDX_VALID(proto_bidx);
23169 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]);
23170 return ret;
23171
23172 api_error:
23173 DUK_ERROR_TYPE_INVALID_ARGS(thr);
23174 DUK_WO_NORETURN(return 0;);
23175}
23176
23177DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
23178 duk_uint_t flags;
23179
23180 DUK_ASSERT_API_ENTRY(thr);
23181
23182 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
23183 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
23184 DUK_HOBJECT_FLAG_CALLABLE |
23185 DUK_HOBJECT_FLAG_FASTREFS |
23186 DUK_HOBJECT_FLAG_NATFUNC |
23187 DUK_HOBJECT_FLAG_NEWENV |
23188 DUK_HOBJECT_FLAG_STRICT |
23189 DUK_HOBJECT_FLAG_NOTAIL |
23190 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
23191
23192 /* Default prototype is a Duktape specific %NativeFunctionPrototype%
23193 * which provides .length and .name getters.
23194 */
23195 return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
23196}
23197
23198DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
23199 duk_uint_t flags;
23200
23201 DUK_ASSERT_API_ENTRY(thr);
23202
23203 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
23204 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
23205 DUK_HOBJECT_FLAG_CALLABLE |
23206 DUK_HOBJECT_FLAG_FASTREFS |
23207 DUK_HOBJECT_FLAG_NATFUNC |
23208 DUK_HOBJECT_FLAG_NEWENV |
23209 DUK_HOBJECT_FLAG_STRICT |
23210 DUK_HOBJECT_FLAG_NOTAIL |
23211 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
23212
23213 /* Must use Function.prototype for standard built-in functions. */
23214 (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
23215}
23216
23217DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
23218 duk_uint_t flags;
23219
23220 DUK_ASSERT_API_ENTRY(thr);
23221
23222 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
23223 DUK_HOBJECT_FLAG_CALLABLE |
23224 DUK_HOBJECT_FLAG_FASTREFS |
23225 DUK_HOBJECT_FLAG_NATFUNC |
23226 DUK_HOBJECT_FLAG_NEWENV |
23227 DUK_HOBJECT_FLAG_STRICT |
23228 DUK_HOBJECT_FLAG_NOTAIL |
23229 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
23230
23231 /* Must use Function.prototype for standard built-in functions. */
23232 (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
23233}
23234
23235DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
23236 duk_small_uint_t lf_flags;
23237 duk_tval *tv_slot;
23238
23239 DUK_ASSERT_API_ENTRY(thr);
23240
23241 DUK__CHECK_SPACE();
23242
23243 if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
23244 /* as is */
23245 } else if (nargs == DUK_VARARGS) {
23246 nargs = DUK_LFUNC_NARGS_VARARGS;
23247 } else {
23248 goto api_error;
23249 }
23250 if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) {
23251 goto api_error;
23252 }
23253 if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) {
23254 goto api_error;
23255 }
23256
23257 lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs);
23258 tv_slot = thr->valstack_top++;
23259 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot));
23260 DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags);
23261 DUK_ASSERT(tv_slot >= thr->valstack_bottom);
23262 return (duk_idx_t) (tv_slot - thr->valstack_bottom);
23263
23264 api_error:
23265 DUK_ERROR_TYPE_INVALID_ARGS(thr);
23266 DUK_WO_NORETURN(return 0;);
23267}
23268
23269#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23270DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
23271 duk_hbufobj *obj;
23272 duk_tval *tv_slot;
23273
23274 DUK_ASSERT_API_ENTRY(thr);
23275 DUK_ASSERT(prototype_bidx >= 0);
23276
23277 DUK__CHECK_SPACE();
23278
23279 obj = duk_hbufobj_alloc(thr, hobject_flags_and_class);
23280 DUK_ASSERT(obj != NULL);
23281
23282 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
23283 DUK_HBUFOBJ_ASSERT_VALID(obj);
23284
23285 tv_slot = thr->valstack_top;
23286 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
23287 DUK_HOBJECT_INCREF(thr, obj);
23288 thr->valstack_top++;
23289
23290 return obj;
23291}
23292#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23293
23294/* XXX: There's quite a bit of overlap with buffer creation handling in
23295 * duk_bi_buffer.c. Look for overlap and refactor.
23296 */
23297#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23298#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \
23299 (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray))
23300
23301static const duk_uint32_t duk__bufobj_flags_lookup[] = {
23302 /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */
23303 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
23304 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */
23305 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */
23306 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
23307 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
23308 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
23309 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
23310 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
23311 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
23312 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
23313 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
23314 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
23315};
23316#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23317
23318#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23319DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
23320 duk_hbufobj *h_bufobj;
23321 duk_hbuffer *h_val;
23322 duk_hobject *h_arraybuf;
23323 duk_uint32_t tmp;
23324 duk_uint_t classnum;
23325 duk_uint_t protobidx;
23326 duk_uint_t lookupidx;
23327 duk_uint_t uint_offset, uint_length, uint_added;
23328
23329 DUK_ASSERT_API_ENTRY(thr);
23330
23331 /* The underlying types for offset/length in duk_hbufobj is
23332 * duk_uint_t; make sure argument values fit.
23333 */
23334 uint_offset = (duk_uint_t) byte_offset;
23335 uint_length = (duk_uint_t) byte_length;
23336 if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
23337 if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) {
23338 goto range_error;
23339 }
23340 }
23341
23342 DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
23343 lookupidx = flags;
23344 if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) {
23345 goto arg_error;
23346 }
23347 tmp = duk__bufobj_flags_lookup[lookupidx];
23348 classnum = tmp >> 24;
23349 protobidx = (tmp >> 16) & 0xff;
23350
23351 h_arraybuf = duk_get_hobject(thr, idx_buffer);
23352 if (h_arraybuf != NULL && /* argument is an object */
23353 flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */
23354 DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) {
23355 duk_uint_t tmp_offset;
23356
23357 DUK_HBUFOBJ_ASSERT_VALID((duk_hbufobj *) h_arraybuf);
23358 h_val = ((duk_hbufobj *) h_arraybuf)->buf;
23359 if (DUK_UNLIKELY(h_val == NULL)) {
23360 goto arg_error;
23361 }
23362
23363 tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset;
23364 if (DUK_UNLIKELY(tmp_offset < uint_offset)) {
23365 goto range_error;
23366 }
23367 uint_offset = tmp_offset;
23368
23369 /* Note intentional difference to new TypedArray(): we allow
23370 * caller to create an uncovered typed array (which is memory
23371 * safe); new TypedArray() rejects it.
23372 */
23373 } else {
23374 /* Handle unexpected object arguments here too, for nice error
23375 * messages.
23376 */
23377 h_arraybuf = NULL;
23378 h_val = duk_require_hbuffer(thr, idx_buffer);
23379 }
23380
23381 /* Wrap check for offset+length. */
23382 uint_added = uint_offset + uint_length;
23383 if (DUK_UNLIKELY(uint_added < uint_offset)) {
23384 goto range_error;
23385 }
23386 DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
23387
23388 DUK_ASSERT(h_val != NULL);
23389
23390 h_bufobj = duk_push_bufobj_raw(thr,
23391 DUK_HOBJECT_FLAG_EXTENSIBLE |
23392 DUK_HOBJECT_FLAG_BUFOBJ |
23393 DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
23394 (duk_small_int_t) protobidx);
23395 DUK_ASSERT(h_bufobj != NULL);
23396
23397 h_bufobj->buf = h_val;
23398 DUK_HBUFFER_INCREF(thr, h_val);
23399 h_bufobj->buf_prop = h_arraybuf;
23400 DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf);
23401 h_bufobj->offset = uint_offset;
23402 h_bufobj->length = uint_length;
23403 h_bufobj->shift = (tmp >> 4) & 0x0f;
23404 h_bufobj->elem_type = (tmp >> 8) & 0xff;
23405 h_bufobj->is_typedarray = tmp & 0x0f;
23406 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
23407
23408 /* TypedArray views need an automatic ArrayBuffer which must be
23409 * provided as .buffer property of the view. The ArrayBuffer is
23410 * referenced via duk_hbufobj->buf_prop and an inherited .buffer
23411 * accessor returns it. The ArrayBuffer is created lazily on first
23412 * access if necessary so we don't need to do anything more here.
23413 */
23414 return;
23415
23416 range_error:
23417 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
23418 DUK_WO_NORETURN(return;);
23419
23420 arg_error:
23421 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
23422 DUK_WO_NORETURN(return;);
23423}
23424#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
23425DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
23426 DUK_ASSERT_API_ENTRY(thr);
23427 DUK_UNREF(idx_buffer);
23428 DUK_UNREF(byte_offset);
23429 DUK_UNREF(byte_length);
23430 DUK_UNREF(flags);
23431 DUK_ERROR_UNSUPPORTED(thr);
23432 DUK_WO_NORETURN(return;);
23433}
23434#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
23435
23436DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
23437 duk_hobject *proto;
23438#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
23439 duk_small_uint_t augment_flags;
23440#endif
23441
23442 DUK_ASSERT_API_ENTRY(thr);
23443 DUK_ASSERT(thr != NULL);
23444 DUK_UNREF(filename);
23445 DUK_UNREF(line);
23446
23447 /* Error code also packs a tracedata related flag. */
23448#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
23449 augment_flags = 0;
23450 if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) {
23451 augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE;
23452 }
23453#endif
23454 err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
23455
23456 /* error gets its 'name' from the prototype */
23457 proto = duk_error_prototype_from_code(thr, err_code);
23458 (void) duk_push_object_helper_proto(thr,
23459 DUK_HOBJECT_FLAG_EXTENSIBLE |
23460 DUK_HOBJECT_FLAG_FASTREFS |
23461 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
23462 proto);
23463
23464 /* ... and its 'message' from an instance property */
23465 if (fmt) {
23466 duk_push_vsprintf(thr, fmt, ap);
23467 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
23468 } else {
23469 /* If no explicit message given, put error code into message field
23470 * (as a number). This is not fully in keeping with the ECMAScript
23471 * error model because messages are supposed to be strings (Error
23472 * constructors use ToString() on their argument). However, it's
23473 * probably more useful than having a separate 'code' property.
23474 */
23475 duk_push_int(thr, err_code);
23476 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
23477 }
23478
23479 /* XXX: .code = err_code disabled, not sure if useful */
23480
23481 /* Creation time error augmentation */
23482#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
23483 /* filename may be NULL in which case file/line is not recorded */
23484 duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */
23485#endif
23486
23487 return duk_get_top_index_unsafe(thr);
23488}
23489
23490DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
23491 va_list ap;
23492 duk_idx_t ret;
23493
23494 DUK_ASSERT_API_ENTRY(thr);
23495
23496 va_start(ap, fmt);
23497 ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23498 va_end(ap);
23499 return ret;
23500}
23501
23502#if !defined(DUK_USE_VARIADIC_MACROS)
23503DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
23504 const char *filename = duk_api_global_filename;
23505 duk_int_t line = duk_api_global_line;
23506 va_list ap;
23507 duk_idx_t ret;
23508
23509 DUK_ASSERT_API_ENTRY(thr);
23510
23511 duk_api_global_filename = NULL;
23512 duk_api_global_line = 0;
23513 va_start(ap, fmt);
23514 ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23515 va_end(ap);
23516 return ret;
23517}
23518#endif /* DUK_USE_VARIADIC_MACROS */
23519
23520DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) {
23521 duk_tval *tv_slot;
23522 duk_hbuffer *h;
23523 void *buf_data;
23524
23525 DUK_ASSERT_API_ENTRY(thr);
23526
23527 DUK__CHECK_SPACE();
23528
23529 /* Check for maximum buffer length. */
23530 if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) {
23531 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
23532 DUK_WO_NORETURN(return NULL;);
23533 }
23534
23535 h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
23536 if (DUK_UNLIKELY(h == NULL)) {
23537 DUK_ERROR_ALLOC_FAILED(thr);
23538 DUK_WO_NORETURN(return NULL;);
23539 }
23540
23541 tv_slot = thr->valstack_top;
23542 DUK_TVAL_SET_BUFFER(tv_slot, h);
23543 DUK_HBUFFER_INCREF(thr, h);
23544 thr->valstack_top++;
23545
23546 return (void *) buf_data;
23547}
23548
23549DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) {
23550 DUK_ASSERT_API_ENTRY(thr);
23551 return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO);
23552}
23553
23554DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) {
23555 void *ptr;
23556
23557 DUK_ASSERT_API_ENTRY(thr);
23558
23559 ptr = duk_push_buffer_raw(thr, len, 0);
23560 DUK_ASSERT(ptr != NULL);
23561#if !defined(DUK_USE_ZERO_BUFFER_DATA)
23562 /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
23563 * is not set.
23564 */
23565 duk_memzero((void *) ptr, (size_t) len);
23566#endif
23567 return ptr;
23568}
23569
23570#if defined(DUK_USE_ES6_PROXY)
23571DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
23572 duk_hobject *h_target;
23573 duk_hobject *h_handler;
23574 duk_hproxy *h_proxy;
23575 duk_tval *tv_slot;
23576 duk_uint_t flags;
23577
23578 DUK_ASSERT_API_ENTRY(thr);
23579 DUK_UNREF(proxy_flags);
23580
23581 /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to
23582 * value stack in-place.
23583 */
23584#if 0
23585 DUK__CHECK_SPACE();
23586#endif
23587
23588 /* Reject a proxy object as the target because it would need
23589 * special handling in property lookups. (ES2015 has no such
23590 * restriction.)
23591 */
23592 h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
23593 DUK_ASSERT(h_target != NULL);
23594 if (DUK_HOBJECT_IS_PROXY(h_target)) {
23595 goto fail_args;
23596 }
23597
23598 /* Reject a proxy object as the handler because it would cause
23599 * potentially unbounded recursion. (ES2015 has no such
23600 * restriction.)
23601 *
23602 * There's little practical reason to use a lightfunc or a plain
23603 * buffer as the handler table: one could only provide traps via
23604 * their prototype objects (Function.prototype and ArrayBuffer.prototype).
23605 * Even so, as lightfuncs and plain buffers mimic their object
23606 * counterparts, they're promoted and accepted here.
23607 */
23608 h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
23609 DUK_ASSERT(h_handler != NULL);
23610 if (DUK_HOBJECT_IS_PROXY(h_handler)) {
23611 goto fail_args;
23612 }
23613
23614 /* XXX: Proxy object currently has no prototype, so ToPrimitive()
23615 * coercion fails which is a bit confusing.
23616 */
23617
23618 /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial)
23619 * target, see ES2015 Sections 9.5.15 and 9.5.13.
23620 */
23621 flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) &
23622 (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE);
23623 flags |= DUK_HOBJECT_FLAG_EXTENSIBLE |
23624 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ;
23625 if (flags & DUK_HOBJECT_FLAG_CALLABLE) {
23626 flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) |
23627 DUK_HOBJECT_FLAG_SPECIAL_CALL;
23628 } else {
23629 flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT);
23630 }
23631
23632 h_proxy = duk_hproxy_alloc(thr, flags);
23633 DUK_ASSERT(h_proxy != NULL);
23634 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL);
23635
23636 /* Initialize Proxy target and handler references; avoid INCREF
23637 * by stealing the value stack refcounts via direct value stack
23638 * manipulation. INCREF is needed for the Proxy itself however.
23639 */
23640 DUK_ASSERT(h_target != NULL);
23641 h_proxy->target = h_target;
23642 DUK_ASSERT(h_handler != NULL);
23643 h_proxy->handler = h_handler;
23644 DUK_HPROXY_ASSERT_VALID(h_proxy);
23645
23646 DUK_ASSERT(duk_get_hobject(thr, -2) == h_target);
23647 DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler);
23648 tv_slot = thr->valstack_top - 2;
23649 DUK_ASSERT(tv_slot >= thr->valstack_bottom);
23650 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy);
23651 DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy);
23652 tv_slot++;
23653 DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */
23654 thr->valstack_top = tv_slot; /* -> [ ... proxy ] */
23655
23656 DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1)));
23657
23658 return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1);
23659
23660 fail_args:
23661 DUK_ERROR_TYPE_INVALID_ARGS(thr);
23662 DUK_WO_NORETURN(return 0;);
23663}
23664#else /* DUK_USE_ES6_PROXY */
23665DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
23666 DUK_ASSERT_API_ENTRY(thr);
23667 DUK_UNREF(proxy_flags);
23668 DUK_ERROR_UNSUPPORTED(thr);
23669 DUK_WO_NORETURN(return 0;);
23670}
23671#endif /* DUK_USE_ES6_PROXY */
23672
23673#if defined(DUK_USE_ASSERTIONS)
23674DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) {
23675 duk_heaphdr *h;
23676 duk_heaphdr *curr;
23677 duk_bool_t found = 0;
23678
23679 h = (duk_heaphdr *) ptr;
23680 if (h == NULL) {
23681 /* Allowed. */
23682 return;
23683 }
23684 DUK_ASSERT(h != NULL);
23685 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
23686
23687 /* One particular problem case is where an object has been
23688 * queued for finalization but the finalizer hasn't yet been
23689 * executed.
23690 *
23691 * Corner case: we're running in a finalizer for object X, and
23692 * user code calls duk_push_heapptr() for X itself. In this
23693 * case X will be in finalize_list, and we can detect the case
23694 * by seeing that X's FINALIZED flag is set (which is done before
23695 * the finalizer starts executing).
23696 */
23697#if defined(DUK_USE_FINALIZER_SUPPORT)
23698 for (curr = thr->heap->finalize_list;
23699 curr != NULL;
23700 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
23701 /* FINALIZABLE is set for all objects on finalize_list
23702 * except for an object being finalized right now. So
23703 * can't assert here.
23704 */
23705#if 0
23706 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr));
23707#endif
23708
23709 if (curr == h) {
23710 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
23711 /* Object is currently being finalized. */
23712 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
23713 found = 1;
23714 } else {
23715 /* Not being finalized but on finalize_list,
23716 * allowed since Duktape 2.1.
23717 */
23718 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
23719 found = 1;
23720 }
23721 }
23722 }
23723#endif /* DUK_USE_FINALIZER_SUPPORT */
23724
23725#if defined(DUK_USE_REFERENCE_COUNTING)
23726 /* Because refzero_list is now processed to completion inline with
23727 * no side effects, it's always empty here.
23728 */
23729 DUK_ASSERT(thr->heap->refzero_list == NULL);
23730#endif
23731
23732 /* If not present in finalize_list (or refzero_list), it
23733 * must be either in heap_allocated or the string table.
23734 */
23735 if (DUK_HEAPHDR_IS_STRING(h)) {
23736 duk_uint32_t i;
23737 duk_hstring *str;
23738 duk_heap *heap = thr->heap;
23739
23740 DUK_ASSERT(found == 0);
23741 for (i = 0; i < heap->st_size; i++) {
23742#if defined(DUK_USE_STRTAB_PTRCOMP)
23743 str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
23744#else
23745 str = heap->strtable[i];
23746#endif
23747 while (str != NULL) {
23748 if (str == (duk_hstring *) h) {
23749 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
23750 found = 1;
23751 break;
23752 }
23753 str = str->hdr.h_next;
23754 }
23755 }
23756 DUK_ASSERT(found != 0);
23757 } else {
23758 for (curr = thr->heap->heap_allocated;
23759 curr != NULL;
23760 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
23761 if (curr == h) {
23762 DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */
23763 found = 1;
23764 }
23765 }
23766 DUK_ASSERT(found != 0);
23767 }
23768}
23769#endif /* DUK_USE_ASSERTIONS */
23770
23771DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) {
23772 duk_idx_t ret;
23773 duk_tval *tv;
23774
23775 DUK_ASSERT_API_ENTRY(thr);
23776
23777 /* Reviving an object using a heap pointer is a dangerous API
23778 * operation: if the application doesn't guarantee that the
23779 * pointer target is always reachable, difficult-to-diagnose
23780 * problems may ensue. Try to validate the 'ptr' argument to
23781 * the extent possible.
23782 */
23783
23784#if defined(DUK_USE_ASSERTIONS)
23785 duk__validate_push_heapptr(thr, ptr);
23786#endif
23787
23788 DUK__CHECK_SPACE();
23789
23790 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
23791 tv = thr->valstack_top++;
23792
23793 if (ptr == NULL) {
23794 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
23795 return ret;
23796 }
23797
23798 DUK_HEAPHDR_ASSERT_VALID((duk_heaphdr *) ptr);
23799
23800 /* If the argument is on finalize_list it has technically been
23801 * unreachable before duk_push_heapptr() but it's still safe to
23802 * push it. Starting from Duktape 2.1 allow application code to
23803 * do so. There are two main cases:
23804 *
23805 * (1) The object is on the finalize_list and we're called by
23806 * the finalizer for the object being finalized. In this
23807 * case do nothing: finalize_list handling will deal with
23808 * the object queueing. This is detected by the object not
23809 * having a FINALIZABLE flag despite being on the finalize_list;
23810 * the flag is cleared for the object being finalized only.
23811 *
23812 * (2) The object is on the finalize_list but is not currently
23813 * being processed. In this case the object can be queued
23814 * back to heap_allocated with a few flags cleared, in effect
23815 * cancelling the finalizer.
23816 */
23817 if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) {
23818 duk_heaphdr *curr;
23819
23820 DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue"));
23821
23822 curr = (duk_heaphdr *) ptr;
23823 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
23824
23825 /* Because FINALIZED is set prior to finalizer call, it will
23826 * be set for the object being currently finalized, but not
23827 * for other objects on finalize_list.
23828 */
23829 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
23830
23831 /* Dequeue object from finalize_list and queue it back to
23832 * heap_allocated.
23833 */
23834#if defined(DUK_USE_REFERENCE_COUNTING)
23835 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */
23836 DUK_HEAPHDR_PREDEC_REFCOUNT(curr);
23837#endif
23838 DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr);
23839 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr);
23840
23841 /* Continue with the rest. */
23842 }
23843
23844 switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
23845 case DUK_HTYPE_STRING:
23846 DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr);
23847 break;
23848 case DUK_HTYPE_OBJECT:
23849 DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr);
23850 break;
23851 default:
23852 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER);
23853 DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr);
23854 break;
23855 }
23856
23857 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr);
23858
23859 return ret;
23860}
23861
23862/* Push object with no prototype, i.e. a "bare" object. */
23863DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) {
23864 DUK_ASSERT_API_ENTRY(thr);
23865
23866 (void) duk_push_object_helper(thr,
23867 DUK_HOBJECT_FLAG_EXTENSIBLE |
23868 DUK_HOBJECT_FLAG_FASTREFS |
23869 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
23870 -1); /* no prototype */
23871 return duk_get_top_index_unsafe(thr);
23872}
23873
23874DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) {
23875 duk_tval tv;
23876
23877 DUK_ASSERT_API_ENTRY(thr);
23878 DUK_ASSERT(h != NULL);
23879
23880 DUK_TVAL_SET_STRING(&tv, h);
23881 duk_push_tval(thr, &tv);
23882}
23883
23884DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
23885 DUK_ASSERT_API_ENTRY(thr);
23886 DUK_ASSERT_STRIDX_VALID(stridx);
23887 duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
23888}
23889
23890DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) {
23891 DUK_ASSERT_API_ENTRY(thr);
23892 duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
23893}
23894
23895DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) {
23896 duk_tval tv;
23897
23898 DUK_ASSERT_API_ENTRY(thr);
23899 DUK_ASSERT(h != NULL);
23900
23901 DUK_TVAL_SET_OBJECT(&tv, h);
23902 duk_push_tval(thr, &tv);
23903}
23904
23905DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
23906 duk_tval tv;
23907
23908 DUK_ASSERT_API_ENTRY(thr);
23909 DUK_ASSERT(h != NULL);
23910
23911 DUK_TVAL_SET_BUFFER(&tv, h);
23912 duk_push_tval(thr, &tv);
23913}
23914
23915DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) {
23916 DUK_ASSERT_API_ENTRY(thr);
23917 DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
23918 DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
23919
23920 duk_push_hobject(thr, thr->builtins[builtin_idx]);
23921}
23922
23923/*
23924 * Poppers
23925 */
23926
23927DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) {
23928 duk_tval *tv;
23929#if defined(DUK_USE_REFERENCE_COUNTING)
23930 duk_tval *tv_end;
23931#endif
23932
23933 DUK_CTX_ASSERT_VALID(thr);
23934 DUK_ASSERT(count >= 0);
23935 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
23936
23937#if defined(DUK_USE_REFERENCE_COUNTING)
23938 tv = thr->valstack_top;
23939 tv_end = tv - count;
23940 while (tv != tv_end) {
23941 tv--;
23942 DUK_ASSERT(tv >= thr->valstack_bottom);
23943 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
23944 }
23945 thr->valstack_top = tv;
23946 DUK_REFZERO_CHECK_FAST(thr);
23947#else
23948 tv = thr->valstack_top;
23949 while (count > 0) {
23950 count--;
23951 tv--;
23952 DUK_ASSERT(tv >= thr->valstack_bottom);
23953 DUK_TVAL_SET_UNDEFINED(tv);
23954 }
23955 thr->valstack_top = tv;
23956#endif
23957
23958 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23959}
23960
23961DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
23962 DUK_ASSERT_API_ENTRY(thr);
23963 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23964
23965 if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
23966 DUK_ERROR_RANGE_INVALID_COUNT(thr);
23967 DUK_WO_NORETURN(return;);
23968 }
23969 DUK_ASSERT(count >= 0);
23970
23971 duk__pop_n_unsafe_raw(thr, count);
23972}
23973
23974#if defined(DUK_USE_PREFER_SIZE)
23975DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
23976 DUK_ASSERT_API_ENTRY(thr);
23977 duk_pop_n(thr, count);
23978}
23979#else /* DUK_USE_PREFER_SIZE */
23980DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
23981 DUK_ASSERT_API_ENTRY(thr);
23982 duk__pop_n_unsafe_raw(thr, count);
23983}
23984#endif /* DUK_USE_PREFER_SIZE */
23985
23986/* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */
23987#if defined(DUK_USE_REFERENCE_COUNTING)
23988DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
23989 duk_tval *tv;
23990
23991 DUK_ASSERT_API_ENTRY(thr);
23992 DUK_ASSERT(count >= 0);
23993 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23994 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
23995
23996 tv = thr->valstack_top;
23997 while (count > 0) {
23998 count--;
23999 tv--;
24000 DUK_ASSERT(tv >= thr->valstack_bottom);
24001 DUK_TVAL_SET_UNDEFINED(tv);
24002 }
24003 thr->valstack_top = tv;
24004
24005 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24006}
24007#else /* DUK_USE_REFERENCE_COUNTING */
24008DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
24009 DUK_ASSERT_API_ENTRY(thr);
24010 duk_pop_n_unsafe(thr, count);
24011}
24012#endif /* DUK_USE_REFERENCE_COUNTING */
24013
24014/* Popping one element is called so often that when footprint is not an issue,
24015 * compile a specialized function for it.
24016 */
24017#if defined(DUK_USE_PREFER_SIZE)
24018DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
24019 DUK_ASSERT_API_ENTRY(thr);
24020 duk_pop_n(thr, 1);
24021}
24022DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
24023 DUK_ASSERT_API_ENTRY(thr);
24024 duk_pop_n_unsafe(thr, 1);
24025}
24026DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
24027 DUK_ASSERT_API_ENTRY(thr);
24028 duk_pop_n_nodecref_unsafe(thr, 1);
24029}
24030#else /* DUK_USE_PREFER_SIZE */
24031DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) {
24032 duk_tval *tv;
24033
24034 DUK_CTX_ASSERT_VALID(thr);
24035 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
24036 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24037 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
24038
24039 tv = --thr->valstack_top;
24040 DUK_ASSERT(tv >= thr->valstack_bottom);
24041#if defined(DUK_USE_REFERENCE_COUNTING)
24042 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
24043#else
24044 DUK_TVAL_SET_UNDEFINED(tv);
24045#endif
24046
24047 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24048}
24049DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
24050 DUK_ASSERT_API_ENTRY(thr);
24051
24052 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24053 if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
24054 DUK_ERROR_RANGE_INVALID_COUNT(thr);
24055 DUK_WO_NORETURN(return;);
24056 }
24057
24058 duk__pop_unsafe_raw(thr);
24059}
24060DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
24061 DUK_ASSERT_API_ENTRY(thr);
24062 duk__pop_unsafe_raw(thr);
24063}
24064DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
24065 duk_tval *tv;
24066
24067 DUK_ASSERT_API_ENTRY(thr);
24068 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
24069 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24070 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
24071
24072 tv = --thr->valstack_top;
24073 DUK_ASSERT(tv >= thr->valstack_bottom);
24074 DUK_TVAL_SET_UNDEFINED(tv);
24075
24076 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24077}
24078#endif /* !DUK_USE_PREFER_SIZE */
24079
24080#if defined(DUK_USE_PREFER_SIZE)
24081DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
24082 DUK_ASSERT_API_ENTRY(thr);
24083 duk_pop_nodecref_unsafe(thr);
24084}
24085#else /* DUK_USE_PREFER_SIZE */
24086DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
24087 DUK_ASSERT_API_ENTRY(thr);
24088 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
24089 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24090 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
24091
24092 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
24093 thr->valstack_top--;
24094
24095 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24096}
24097#endif /* !DUK_USE_PREFER_SIZE */
24098
24099#if defined(DUK_USE_PREFER_SIZE)
24100DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
24101 DUK_ASSERT_API_ENTRY(thr);
24102 duk_pop_n(thr, 2);
24103}
24104DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
24105 DUK_ASSERT_API_ENTRY(thr);
24106 duk_pop_n_unsafe(thr, 2);
24107}
24108DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
24109 DUK_ASSERT_API_ENTRY(thr);
24110 duk_pop_n_nodecref_unsafe(thr, 2);
24111}
24112#else
24113DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) {
24114 duk_tval *tv;
24115
24116 DUK_CTX_ASSERT_VALID(thr);
24117 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
24118 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24119 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
24120
24121 tv = --thr->valstack_top;
24122 DUK_ASSERT(tv >= thr->valstack_bottom);
24123#if defined(DUK_USE_REFERENCE_COUNTING)
24124 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
24125#else
24126 DUK_TVAL_SET_UNDEFINED(tv);
24127#endif
24128 tv = --thr->valstack_top;
24129 DUK_ASSERT(tv >= thr->valstack_bottom);
24130#if defined(DUK_USE_REFERENCE_COUNTING)
24131 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
24132#else
24133 DUK_TVAL_SET_UNDEFINED(tv);
24134#endif
24135
24136 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24137}
24138DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
24139 DUK_ASSERT_API_ENTRY(thr);
24140
24141 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24142 if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
24143 DUK_ERROR_RANGE_INVALID_COUNT(thr);
24144 DUK_WO_NORETURN(return;);
24145 }
24146
24147 duk__pop_2_unsafe_raw(thr);
24148}
24149DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
24150 DUK_ASSERT_API_ENTRY(thr);
24151 duk__pop_2_unsafe_raw(thr);
24152}
24153DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
24154 DUK_ASSERT_API_ENTRY(thr);
24155 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
24156 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24157 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
24158
24159 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
24160 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2));
24161 thr->valstack_top -= 2;
24162
24163 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24164}
24165#endif /* !DUK_USE_PREFER_SIZE */
24166
24167DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) {
24168 DUK_ASSERT_API_ENTRY(thr);
24169 duk_pop_n(thr, 3);
24170}
24171
24172DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) {
24173 DUK_ASSERT_API_ENTRY(thr);
24174 duk_pop_n_unsafe(thr, 3);
24175}
24176
24177DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) {
24178 DUK_ASSERT_API_ENTRY(thr);
24179 duk_pop_n_nodecref_unsafe(thr, 3);
24180}
24181
24182/*
24183 * Pack and unpack (pack value stack entries into an array and vice versa)
24184 */
24185
24186/* XXX: pack index range? array index offset? */
24187/* XXX: need ability to pack into a bare array? */
24188DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
24189 duk_tval *tv_src;
24190 duk_tval *tv_dst;
24191 duk_tval *tv_curr;
24192 duk_tval *tv_limit;
24193 duk_idx_t top;
24194
24195 DUK_ASSERT_API_ENTRY(thr);
24196
24197 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24198 top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
24199 DUK_ASSERT(top >= 0);
24200 if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
24201 /* Also handles negative count. */
24202 DUK_ERROR_RANGE_INVALID_COUNT(thr);
24203 DUK_WO_NORETURN(return;);
24204 }
24205 DUK_ASSERT(count >= 0);
24206
24207 /* Wrapping is controlled by the check above: value stack top can be
24208 * at most DUK_USE_VALSTACK_LIMIT which is low enough so that
24209 * multiplying with sizeof(duk_tval) won't wrap.
24210 */
24211 DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT);
24212 DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */
24213
24214 tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
24215 DUK_ASSERT(count == 0 || tv_dst != NULL);
24216 DUK_ASSERT(!duk_is_bare_object(thr, -1));
24217
24218 /* Copy value stack values directly to the array part without
24219 * any refcount updates: net refcount changes are zero.
24220 */
24221 tv_src = thr->valstack_top - count - 1;
24222 duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
24223
24224 /* Overwrite result array to final value stack location and wipe
24225 * the rest; no refcount operations needed.
24226 */
24227
24228 tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */
24229 tv_src = thr->valstack_top - 1;
24230 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
24231
24232 /* XXX: internal helper to wipe a value stack segment? */
24233 tv_curr = tv_dst + 1;
24234 tv_limit = thr->valstack_top;
24235 while (tv_curr != tv_limit) {
24236 /* Wipe policy: keep as 'undefined'. */
24237 DUK_TVAL_SET_UNDEFINED(tv_curr);
24238 tv_curr++;
24239 }
24240 thr->valstack_top = tv_dst + 1;
24241}
24242
24243DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
24244 duk_tval *tv;
24245
24246 DUK_ASSERT_API_ENTRY(thr);
24247
24248 tv = duk_require_tval(thr, idx);
24249 if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) {
24250 duk_hobject *h;
24251 duk_uint32_t len;
24252 duk_uint32_t i;
24253
24254 h = DUK_TVAL_GET_OBJECT(tv);
24255 DUK_ASSERT(h != NULL);
24256 DUK_UNREF(h);
24257
24258#if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */
24259 if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) &&
24260 ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) {
24261 duk_harray *h_arr;
24262 duk_tval *tv_src;
24263 duk_tval *tv_dst;
24264
24265 h_arr = (duk_harray *) h;
24266 len = h_arr->length;
24267 if (DUK_UNLIKELY(len >= 0x80000000UL)) {
24268 goto fail_over_2g;
24269 }
24270 duk_require_stack(thr, (duk_idx_t) len);
24271
24272 /* The potential allocation in duk_require_stack() may
24273 * run a finalizer which modifies the argArray so that
24274 * e.g. becomes sparse. So, we need to recheck that the
24275 * array didn't change size and that there's still a
24276 * valid backing array part.
24277 *
24278 * XXX: alternatively, could prevent finalizers for the
24279 * duration.
24280 */
24281 if (DUK_UNLIKELY(len != h_arr->length ||
24282 h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) {
24283 goto skip_fast;
24284 }
24285
24286 /* Main fast path: arguments array is almost always
24287 * an actual array (though it might also be an arguments
24288 * object).
24289 */
24290
24291 DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length));
24292 tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
24293 tv_dst = thr->valstack_top;
24294 while (len-- > 0) {
24295 DUK_ASSERT(tv_dst < thr->valstack_end);
24296 if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) {
24297 /* Gaps are very unlikely. Skip over them,
24298 * without an ancestor lookup (technically
24299 * not compliant).
24300 */
24301 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */
24302 } else {
24303 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
24304 DUK_TVAL_INCREF(thr, tv_dst);
24305 }
24306 tv_src++;
24307 tv_dst++;
24308 }
24309 DUK_ASSERT(tv_dst <= thr->valstack_end);
24310 thr->valstack_top = tv_dst;
24311 return (duk_idx_t) h_arr->length;
24312 }
24313 skip_fast:
24314#endif /* DUK_USE_ARRAY_FASTPATH */
24315
24316 /* Slow path: actual lookups. The initial 'length' lookup
24317 * decides the output length, regardless of side effects that
24318 * may resize or change the argArray while we read the
24319 * indices.
24320 */
24321 idx = duk_normalize_index(thr, idx);
24322 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
24323 len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */
24324 if (DUK_UNLIKELY(len >= 0x80000000UL)) {
24325 goto fail_over_2g;
24326 }
24327 duk_pop_unsafe(thr);
24328 DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len));
24329
24330 duk_require_stack(thr, (duk_idx_t) len);
24331 for (i = 0; i < len; i++) {
24332 duk_get_prop_index(thr, idx, (duk_uarridx_t) i);
24333 }
24334 return (duk_idx_t) len;
24335 } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
24336 return 0;
24337 }
24338
24339 DUK_ERROR_TYPE_INVALID_ARGS(thr);
24340 DUK_WO_NORETURN(return 0;);
24341
24342 fail_over_2g:
24343 DUK_ERROR_RANGE_INVALID_LENGTH(thr);
24344 DUK_WO_NORETURN(return 0;);
24345}
24346
24347/*
24348 * Error throwing
24349 */
24350
24351#if defined(DUK_USE_GCC_PRAGMAS)
24352#pragma GCC diagnostic push
24353#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
24354#elif defined(DUK_USE_CLANG_PRAGMAS)
24355#pragma clang diagnostic push
24356#endif
24357
24358DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
24359 duk_tval *tv_val;
24360
24361 DUK_ASSERT_API_ENTRY(thr);
24362 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
24363 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
24364 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
24365
24366 if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
24367 DUK_ERROR_TYPE_INVALID_ARGS(thr);
24368 DUK_WO_NORETURN(return;);
24369 }
24370
24371 /* Errors are augmented when they are created, not when they are
24372 * thrown or re-thrown. The current error handler, however, runs
24373 * just before an error is thrown.
24374 */
24375
24376 /* Sync so that augmentation sees up-to-date activations, NULL
24377 * thr->ptr_curr_pc so that it's not used if side effects occur
24378 * in augmentation or longjmp handling.
24379 */
24380 duk_hthread_sync_and_null_currpc(thr);
24381
24382#if defined(DUK_USE_AUGMENT_ERROR_THROW)
24383 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
24384 duk_err_augment_error_throw(thr);
24385#endif
24386 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
24387
24388 tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
24389 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val);
24390#if defined(DUK_USE_DEBUGGER_SUPPORT)
24391 duk_err_check_debugger_integration(thr);
24392#endif
24393
24394 /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
24395 * need to check that here. If the value is NULL, a fatal error occurs
24396 * because we can't return.
24397 */
24398
24399 duk_err_longjmp(thr);
24400 DUK_UNREACHABLE();
24401}
24402
24403DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) {
24404 DUK_ASSERT_API_ENTRY(thr);
24405 DUK_ASSERT(thr != NULL);
24406 DUK_ASSERT(thr->heap != NULL);
24407 DUK_ASSERT(thr->heap->fatal_func != NULL);
24408
24409 DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL"));
24410
24411 /* fatal_func should be noreturn, but noreturn declarations on function
24412 * pointers has a very spotty support apparently so it's not currently
24413 * done.
24414 */
24415 thr->heap->fatal_func(thr->heap->heap_udata, err_msg);
24416
24417 /* If the fatal handler returns, all bets are off. It'd be nice to
24418 * print something here but since we don't want to depend on stdio,
24419 * there's no way to do so portably.
24420 */
24421 DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!"));
24422 for (;;) {
24423 /* loop forever, don't return (function marked noreturn) */
24424 }
24425}
24426
24427DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
24428 DUK_ASSERT_API_ENTRY(thr);
24429
24430 duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
24431 (void) duk_throw(thr);
24432 DUK_WO_NORETURN(return;);
24433}
24434
24435DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
24436 va_list ap;
24437
24438 DUK_ASSERT_API_ENTRY(thr);
24439
24440 va_start(ap, fmt);
24441 duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
24442 va_end(ap);
24443 (void) duk_throw(thr);
24444 DUK_WO_NORETURN(return;);
24445}
24446
24447#if defined(DUK_USE_GCC_PRAGMAS)
24448#pragma GCC diagnostic pop
24449#elif defined(DUK_USE_CLANG_PRAGMAS)
24450#pragma clang diagnostic pop
24451#endif
24452
24453#if !defined(DUK_USE_VARIADIC_MACROS)
24454DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap));
24455
24456DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) {
24457 const char *filename;
24458 duk_int_t line;
24459
24460 DUK_CTX_ASSERT_VALID(thr);
24461
24462 filename = duk_api_global_filename;
24463 line = duk_api_global_line;
24464 duk_api_global_filename = NULL;
24465 duk_api_global_line = 0;
24466
24467 duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
24468 (void) duk_throw(thr);
24469 DUK_WO_NORETURN(return;);
24470}
24471
24472#define DUK__ERROR_STASH_SHARED(code) do { \
24473 va_list ap; \
24474 va_start(ap, fmt); \
24475 duk__throw_error_from_stash(thr, (code), fmt, ap); \
24476 va_end(ap); \
24477 DUK_WO_NORETURN(return 0;); \
24478 } while (0)
24479
24480DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
24481 DUK_ASSERT_API_ENTRY(thr);
24482 DUK__ERROR_STASH_SHARED(err_code);
24483}
24484DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) {
24485 DUK_ASSERT_API_ENTRY(thr);
24486 DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
24487}
24488DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) {
24489 DUK_ASSERT_API_ENTRY(thr);
24490 DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
24491}
24492DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) {
24493 DUK_ASSERT_API_ENTRY(thr);
24494 DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
24495}
24496DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) {
24497 DUK_ASSERT_API_ENTRY(thr);
24498 DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
24499}
24500DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) {
24501 DUK_ASSERT_API_ENTRY(thr);
24502 DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
24503}
24504DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) {
24505 DUK_ASSERT_API_ENTRY(thr);
24506 DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
24507}
24508DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) {
24509 DUK_ASSERT_API_ENTRY(thr);
24510 DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
24511}
24512#endif /* DUK_USE_VARIADIC_MACROS */
24513
24514/*
24515 * Comparison
24516 */
24517
24518DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24519 duk_tval *tv1, *tv2;
24520
24521 DUK_ASSERT_API_ENTRY(thr);
24522
24523 tv1 = duk_get_tval(thr, idx1);
24524 tv2 = duk_get_tval(thr, idx2);
24525 if ((tv1 == NULL) || (tv2 == NULL)) {
24526 return 0;
24527 }
24528
24529 /* Coercion may be needed, the helper handles that by pushing the
24530 * tagged values to the stack.
24531 */
24532 return duk_js_equals(thr, tv1, tv2);
24533}
24534
24535DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24536 duk_tval *tv1, *tv2;
24537
24538 DUK_ASSERT_API_ENTRY(thr);
24539
24540 tv1 = duk_get_tval(thr, idx1);
24541 tv2 = duk_get_tval(thr, idx2);
24542 if ((tv1 == NULL) || (tv2 == NULL)) {
24543 return 0;
24544 }
24545
24546 /* No coercions or other side effects, so safe */
24547 return duk_js_strict_equals(tv1, tv2);
24548}
24549
24550DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24551 duk_tval *tv1, *tv2;
24552
24553 DUK_ASSERT_API_ENTRY(thr);
24554
24555 tv1 = duk_get_tval(thr, idx1);
24556 tv2 = duk_get_tval(thr, idx2);
24557 if ((tv1 == NULL) || (tv2 == NULL)) {
24558 return 0;
24559 }
24560
24561 /* No coercions or other side effects, so safe */
24562 return duk_js_samevalue(tv1, tv2);
24563}
24564
24565/*
24566 * instanceof
24567 */
24568
24569DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24570 duk_tval *tv1, *tv2;
24571
24572 DUK_ASSERT_API_ENTRY(thr);
24573
24574 /* Index validation is strict, which differs from duk_equals().
24575 * The strict behavior mimics how instanceof itself works, e.g.
24576 * it is a TypeError if rval is not a -callable- object. It would
24577 * be somewhat inconsistent if rval would be allowed to be
24578 * non-existent without a TypeError.
24579 */
24580 tv1 = duk_require_tval(thr, idx1);
24581 DUK_ASSERT(tv1 != NULL);
24582 tv2 = duk_require_tval(thr, idx2);
24583 DUK_ASSERT(tv2 != NULL);
24584
24585 return duk_js_instanceof(thr, tv1, tv2);
24586}
24587
24588/*
24589 * Lightfunc
24590 */
24591
24592DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
24593 /* Lightfunc name, includes Duktape/C native function pointer, which
24594 * can often be used to locate the function from a symbol table.
24595 * The name also includes the 16-bit duk_tval flags field because it
24596 * includes the magic value. Because a single native function often
24597 * provides different functionality depending on the magic value, it
24598 * seems reasonably to include it in the name.
24599 *
24600 * On the other hand, a complicated name increases string table
24601 * pressure in low memory environments (but only when function name
24602 * is accessed).
24603 */
24604
24605 DUK_ASSERT_API_ENTRY(thr);
24606
24607 duk_push_literal(thr, "light_");
24608 duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
24609 duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
24610 duk_concat(thr, 3);
24611}
24612
24613DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) {
24614 duk_c_function func;
24615 duk_small_uint_t lf_flags;
24616
24617 DUK_ASSERT_API_ENTRY(thr);
24618 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
24619
24620 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
24621 duk_push_lightfunc_name_raw(thr, func, lf_flags);
24622}
24623
24624DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
24625 duk_c_function func;
24626 duk_small_uint_t lf_flags;
24627
24628 DUK_ASSERT_API_ENTRY(thr);
24629 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
24630
24631 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
24632 duk_push_literal(thr, "function ");
24633 duk_push_lightfunc_name_raw(thr, func, lf_flags);
24634 duk_push_literal(thr, "() { [lightfunc code] }");
24635 duk_concat(thr, 3);
24636}
24637
24638/*
24639 * Function pointers
24640 *
24641 * Printing function pointers is non-portable, so we do that by hex printing
24642 * bytes from memory.
24643 */
24644
24645DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) {
24646 duk_uint8_t buf[32 * 2];
24647 duk_uint8_t *p, *q;
24648 duk_small_uint_t i;
24649 duk_small_uint_t t;
24650
24651 DUK_ASSERT_API_ENTRY(thr);
24652 DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
24653
24654 p = buf;
24655#if defined(DUK_USE_INTEGER_LE)
24656 q = ptr + sz;
24657#else
24658 q = ptr;
24659#endif
24660 for (i = 0; i < sz; i++) {
24661#if defined(DUK_USE_INTEGER_LE)
24662 t = *(--q);
24663#else
24664 t = *(q++);
24665#endif
24666 *p++ = duk_lc_digits[t >> 4];
24667 *p++ = duk_lc_digits[t & 0x0f];
24668 }
24669
24670 duk_push_lstring(thr, (const char *) buf, sz * 2);
24671}
24672
24673/*
24674 * Push readable string summarizing duk_tval. The operation is side effect
24675 * free and will only throw from internal errors (e.g. out of memory).
24676 * This is used by e.g. property access code to summarize a key/base safely,
24677 * and is not intended to be fast (but small and safe).
24678 */
24679
24680/* String limits for summary strings. */
24681#define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */
24682#define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */
24683#define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */
24684
24685/* String sanitizer which escapes ASCII control characters and a few other
24686 * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
24687 * question marks. No errors are thrown for any input string, except in out
24688 * of memory situations.
24689 */
24690DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) {
24691 const duk_uint8_t *p, *p_start, *p_end;
24692 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS +
24693 2 /*quotes*/ + 3 /*periods*/];
24694 duk_uint8_t *q;
24695 duk_ucodepoint_t cp;
24696 duk_small_uint_t nchars;
24697
24698 DUK_CTX_ASSERT_VALID(thr);
24699 DUK_ASSERT(h_input != NULL);
24700 DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS);
24701
24702 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
24703 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
24704 p = p_start;
24705 q = buf;
24706
24707 nchars = 0;
24708 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
24709 for (;;) {
24710 if (p >= p_end) {
24711 break;
24712 }
24713 if (nchars == maxchars) {
24714 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24715 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24716 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24717 break;
24718 }
24719 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
24720 if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
24721 DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
24722 DUK_ASSERT((cp >> 4) <= 0x0f);
24723 *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
24724 *q++ = (duk_uint8_t) DUK_ASC_LC_X;
24725 *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
24726 *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
24727 } else {
24728 q += duk_unicode_encode_xutf8(cp, q);
24729 }
24730 } else {
24731 p++; /* advance manually */
24732 *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
24733 }
24734 nchars++;
24735 }
24736 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
24737
24738 duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf));
24739}
24740
24741DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) {
24742 DUK_CTX_ASSERT_VALID(thr);
24743 /* 'tv' may be NULL */
24744
24745 if (tv == NULL) {
24746 duk_push_literal(thr, "none");
24747 } else {
24748 switch (DUK_TVAL_GET_TAG(tv)) {
24749 case DUK_TAG_STRING: {
24750 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
24751 if (DUK_HSTRING_HAS_SYMBOL(h)) {
24752 /* XXX: string summary produces question marks
24753 * so this is not very ideal.
24754 */
24755 duk_push_literal(thr, "[Symbol ");
24756 duk_push_string(thr, duk__get_symbol_type_string(h));
24757 duk_push_literal(thr, " ");
24758 duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
24759 duk_push_literal(thr, "]");
24760 duk_concat(thr, 5);
24761 break;
24762 }
24763 duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
24764 break;
24765 }
24766 case DUK_TAG_OBJECT: {
24767 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
24768 DUK_ASSERT(h != NULL);
24769
24770 if (error_aware &&
24771 duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
24772 /* Get error message in a side effect free way if
24773 * possible; if not, summarize as a generic object.
24774 * Error message currently gets quoted.
24775 */
24776 /* XXX: better internal getprop call; get without side effects
24777 * but traverse inheritance chain.
24778 */
24779 duk_tval *tv_msg;
24780 tv_msg = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, h, DUK_STRIDX_MESSAGE);
24781 if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) {
24782 /* It's critical to avoid recursion so
24783 * only summarize a string .message.
24784 */
24785 duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS);
24786 break;
24787 }
24788 }
24789 duk_push_class_string_tval(thr, tv, 1 /*avoid_side_effects*/);
24790 break;
24791 }
24792 case DUK_TAG_BUFFER: {
24793 /* While plain buffers mimic Uint8Arrays, they summarize differently.
24794 * This is useful so that the summarized string accurately reflects the
24795 * internal type which may matter for figuring out bugs etc.
24796 */
24797 /* XXX: Hex encoded, length limited buffer summary here? */
24798 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
24799 DUK_ASSERT(h != NULL);
24800 duk_push_sprintf(thr, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
24801 break;
24802 }
24803 case DUK_TAG_POINTER: {
24804 /* Surround with parentheses like in JX, ensures NULL pointer
24805 * is distinguishable from null value ("(null)" vs "null").
24806 */
24807 duk_push_tval(thr, tv);
24808 duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1));
24809 duk_remove_m2(thr);
24810 break;
24811 }
24812 default: {
24813 duk_push_tval(thr, tv);
24814 break;
24815 }
24816 }
24817 }
24818
24819 return duk_to_string(thr, -1);
24820}
24821DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) {
24822 DUK_ASSERT_API_ENTRY(thr);
24823 return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/);
24824}
24825
24826DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) {
24827 DUK_ASSERT_API_ENTRY(thr);
24828 return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx));
24829}
24830
24831DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) {
24832 DUK_ASSERT_API_ENTRY(thr);
24833 return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/);
24834}
24835
24836DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) {
24837 const duk_uint8_t *p;
24838 const duk_uint8_t *p_end;
24839 const duk_uint8_t *q;
24840
24841 DUK_ASSERT_API_ENTRY(thr);
24842
24843 /* .toString() */
24844 duk_push_literal(thr, "Symbol(");
24845 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
24846 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
24847 DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
24848 p++;
24849 for (q = p; q < p_end; q++) {
24850 if (*q == 0xffU) {
24851 /* Terminate either at end-of-string (but NUL MUST
24852 * be accepted without terminating description) or
24853 * 0xFF, which is used to mark start of unique trailer
24854 * (and cannot occur in CESU-8 / extended UTF-8).
24855 */
24856 break;
24857 }
24858 }
24859 duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
24860 duk_push_literal(thr, ")");
24861 duk_concat(thr, 3);
24862}
24863
24864/*
24865 * Functions
24866 */
24867
24868#if 0 /* not used yet */
24869DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) {
24870 duk_c_function func;
24871
24872 DUK_ASSERT_API_ENTRY(thr);
24873 DUK_ASSERT(h != NULL);
24874 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h));
24875
24876 duk_push_sprintf(thr, "native_");
24877 func = h->func;
24878 duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
24879 duk_push_sprintf(thr, "_%04x_%04x",
24880 (unsigned int) (duk_uint16_t) h->nargs,
24881 (unsigned int) (duk_uint16_t) h->magic);
24882 duk_concat(thr, 3);
24883}
24884#endif
24885
24886/*
24887 * duk_tval slice copy
24888 */
24889
24890DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) {
24891 duk_tval *tv;
24892
24893 DUK_ASSERT_API_ENTRY(thr);
24894 DUK_UNREF(thr);
24895 DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
24896
24897 duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
24898
24899 tv = tv_dst;
24900 while (count-- > 0) {
24901 DUK_TVAL_INCREF(thr, tv);
24902 tv++;
24903 }
24904}
24905
24906/* automatic undefs */
24907#undef DUK__ASSERT_SPACE
24908#undef DUK__CHECK_SPACE
24909#undef DUK__ERROR_STASH_SHARED
24910#undef DUK__PACK_ARGS
24911#undef DUK__READABLE_ERRMSG_MAXCHARS
24912#undef DUK__READABLE_STRING_MAXCHARS
24913#undef DUK__READABLE_SUMMARY_MAXCHARS
24914#line 1 "duk_api_string.c"
24915/*
24916 * String manipulation
24917 */
24918
24919/* #include duk_internal.h -> already included */
24920
24921DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
24922 duk_uint_t count;
24923 duk_uint_t i;
24924 duk_size_t idx;
24925 duk_size_t len;
24926 duk_hstring *h;
24927 duk_uint8_t *buf;
24928
24929 DUK_CTX_ASSERT_VALID(thr);
24930
24931 if (DUK_UNLIKELY(count_in <= 0)) {
24932 if (count_in < 0) {
24933 DUK_ERROR_RANGE_INVALID_COUNT(thr);
24934 DUK_WO_NORETURN(return;);
24935 }
24936 DUK_ASSERT(count_in == 0);
24937 duk_push_hstring_empty(thr);
24938 return;
24939 }
24940 count = (duk_uint_t) count_in;
24941
24942 if (is_join) {
24943 duk_size_t t1, t2, limit;
24944 h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
24945 DUK_ASSERT(h != NULL);
24946
24947 /* A bit tricky overflow test, see doc/code-issues.rst. */
24948 t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
24949 t2 = (duk_size_t) (count - 1);
24950 limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
24951 if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
24952 /* Combined size of separators already overflows. */
24953 goto error_overflow;
24954 }
24955 len = (duk_size_t) (t1 * t2);
24956 } else {
24957 len = (duk_size_t) 0;
24958 }
24959
24960 for (i = count; i >= 1; i--) {
24961 duk_size_t new_len;
24962 h = duk_to_hstring(thr, -((duk_idx_t) i));
24963 new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
24964
24965 /* Impose a string maximum length, need to handle overflow
24966 * correctly.
24967 */
24968 if (new_len < len || /* wrapped */
24969 new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
24970 goto error_overflow;
24971 }
24972 len = new_len;
24973 }
24974
24975 DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
24976 (unsigned long) count, (unsigned long) len));
24977
24978 /* Use stack allocated buffer to ensure reachability in errors
24979 * (e.g. intern error).
24980 */
24981 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
24982 DUK_ASSERT(buf != NULL);
24983
24984 /* [ ... (sep) str1 str2 ... strN buf ] */
24985
24986 idx = 0;
24987 for (i = count; i >= 1; i--) {
24988 if (is_join && i != count) {
24989 h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
24990 duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
24991 idx += DUK_HSTRING_GET_BYTELEN(h);
24992 }
24993 h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
24994 duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
24995 idx += DUK_HSTRING_GET_BYTELEN(h);
24996 }
24997
24998 DUK_ASSERT(idx == len);
24999
25000 /* [ ... (sep) str1 str2 ... strN buf ] */
25001
25002 /* Get rid of the strings early to minimize memory use before intern. */
25003
25004 if (is_join) {
25005 duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */
25006 duk_pop_n(thr, (duk_idx_t) count);
25007 } else {
25008 duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */
25009 duk_pop_n(thr, (duk_idx_t) (count - 1));
25010 }
25011
25012 /* [ ... buf ] */
25013
25014 (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
25015
25016 /* [ ... res ] */
25017 return;
25018
25019 error_overflow:
25020 DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
25021 DUK_WO_NORETURN(return;);
25022}
25023
25024DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
25025 DUK_ASSERT_API_ENTRY(thr);
25026
25027 duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
25028}
25029
25030#if defined(DUK_USE_PREFER_SIZE)
25031DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
25032 DUK_ASSERT_API_ENTRY(thr);
25033 duk_concat(thr, 2);
25034}
25035#else /* DUK_USE_PREFER_SIZE */
25036DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
25037 duk_hstring *h1;
25038 duk_hstring *h2;
25039 duk_uint8_t *buf;
25040 duk_size_t len1;
25041 duk_size_t len2;
25042 duk_size_t len;
25043
25044 DUK_ASSERT_API_ENTRY(thr);
25045 DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */
25046
25047 h1 = duk_to_hstring(thr, -2);
25048 h2 = duk_to_hstring(thr, -1);
25049 len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
25050 len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
25051 len = len1 + len2;
25052 if (DUK_UNLIKELY(len < len1 || /* wrapped */
25053 len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
25054 goto error_overflow;
25055 }
25056 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
25057 DUK_ASSERT(buf != NULL);
25058
25059 duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
25060 duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
25061 (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
25062
25063 /* [ ... str1 str2 buf ] */
25064
25065 duk_replace(thr, -3);
25066 duk_pop_unsafe(thr);
25067 return;
25068
25069 error_overflow:
25070 DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
25071 DUK_WO_NORETURN(return;);
25072}
25073#endif /* DUK_USE_PREFER_SIZE */
25074
25075DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
25076 DUK_ASSERT_API_ENTRY(thr);
25077
25078 duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
25079}
25080
25081/* XXX: could map/decode be unified with duk_unicode_support.c code?
25082 * Case conversion needs also the character surroundings though.
25083 */
25084
25085DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
25086 duk_hstring *h_input;
25087 const duk_uint8_t *p, *p_start, *p_end;
25088 duk_codepoint_t cp;
25089
25090 DUK_ASSERT_API_ENTRY(thr);
25091
25092 h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
25093 DUK_ASSERT(h_input != NULL);
25094
25095 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
25096 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
25097 p = p_start;
25098
25099 for (;;) {
25100 if (p >= p_end) {
25101 break;
25102 }
25103 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
25104 callback(udata, cp);
25105 }
25106}
25107
25108DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
25109 duk_hstring *h_input;
25110 duk_bufwriter_ctx bw_alloc;
25111 duk_bufwriter_ctx *bw;
25112 const duk_uint8_t *p, *p_start, *p_end;
25113 duk_codepoint_t cp;
25114
25115 DUK_ASSERT_API_ENTRY(thr);
25116
25117 idx = duk_normalize_index(thr, idx);
25118
25119 h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
25120 DUK_ASSERT(h_input != NULL);
25121
25122 bw = &bw_alloc;
25123 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */
25124
25125 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
25126 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
25127 p = p_start;
25128
25129 for (;;) {
25130 /* XXX: could write output in chunks with fewer ensure calls,
25131 * but relative benefit would be small here.
25132 */
25133
25134 if (p >= p_end) {
25135 break;
25136 }
25137 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
25138 cp = callback(udata, cp);
25139
25140 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
25141 }
25142
25143 DUK_BW_COMPACT(thr, bw);
25144 (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */
25145 duk_replace(thr, idx);
25146}
25147
25148DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
25149 duk_hstring *h;
25150 duk_hstring *res;
25151 duk_size_t start_byte_offset;
25152 duk_size_t end_byte_offset;
25153 duk_size_t charlen;
25154
25155 DUK_ASSERT_API_ENTRY(thr);
25156
25157 idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
25158 h = duk_require_hstring(thr, idx);
25159 DUK_ASSERT(h != NULL);
25160
25161 charlen = DUK_HSTRING_GET_CHARLEN(h);
25162 if (end_offset >= charlen) {
25163 end_offset = charlen;
25164 }
25165 if (start_offset > end_offset) {
25166 start_offset = end_offset;
25167 }
25168
25169 DUK_ASSERT_DISABLE(start_offset >= 0);
25170 DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
25171 DUK_ASSERT_DISABLE(end_offset >= 0);
25172 DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
25173
25174 /* Guaranteed by string limits. */
25175 DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
25176 DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
25177
25178 start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
25179 end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
25180
25181 DUK_ASSERT(end_byte_offset >= start_byte_offset);
25182 DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */
25183
25184 /* No size check is necessary. */
25185 res = duk_heap_strtable_intern_checked(thr,
25186 DUK_HSTRING_GET_DATA(h) + start_byte_offset,
25187 (duk_uint32_t) (end_byte_offset - start_byte_offset));
25188
25189 duk_push_hstring(thr, res);
25190 duk_replace(thr, idx);
25191}
25192
25193/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
25194 * forwards with a callback to process codepoints?
25195 */
25196DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
25197 duk_hstring *h;
25198 const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
25199 const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
25200 duk_codepoint_t cp;
25201
25202 DUK_ASSERT_API_ENTRY(thr);
25203
25204 idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
25205 h = duk_require_hstring(thr, idx);
25206 DUK_ASSERT(h != NULL);
25207
25208 p_start = DUK_HSTRING_GET_DATA(h);
25209 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
25210
25211 p = p_start;
25212 while (p < p_end) {
25213 p_tmp1 = p;
25214 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
25215 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
25216 break;
25217 }
25218 p = p_tmp1;
25219 }
25220 q_start = p;
25221 if (p == p_end) {
25222 /* Entire string is whitespace. */
25223 q_end = p;
25224 goto scan_done;
25225 }
25226
25227 p = p_end;
25228 while (p > p_start) {
25229 p_tmp1 = p;
25230 while (p > p_start) {
25231 p--;
25232 if (((*p) & 0xc0) != 0x80) {
25233 break;
25234 }
25235 }
25236 p_tmp2 = p;
25237
25238 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
25239 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
25240 p = p_tmp1;
25241 break;
25242 }
25243 }
25244 q_end = p;
25245
25246 scan_done:
25247 /* This may happen when forward and backward scanning disagree
25248 * (possible for non-extended-UTF-8 strings).
25249 */
25250 if (q_end < q_start) {
25251 q_end = q_start;
25252 }
25253
25254 DUK_ASSERT(q_start >= p_start && q_start <= p_end);
25255 DUK_ASSERT(q_end >= p_start && q_end <= p_end);
25256 DUK_ASSERT(q_end >= q_start);
25257
25258 DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
25259 (const void *) p_start, (const void *) p_end,
25260 (const void *) q_start, (const void *) q_end));
25261
25262 if (q_start == p_start && q_end == p_end) {
25263 DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
25264 return;
25265 }
25266
25267 duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
25268 duk_replace(thr, idx);
25269}
25270
25271DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
25272 duk_hstring *h;
25273 duk_ucodepoint_t cp;
25274
25275 DUK_ASSERT_API_ENTRY(thr);
25276
25277 /* XXX: Share code with String.prototype.charCodeAt? Main difference
25278 * is handling of clamped offsets.
25279 */
25280
25281 h = duk_require_hstring(thr, idx); /* Accept symbols. */
25282 DUK_ASSERT(h != NULL);
25283
25284 DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
25285 if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
25286 return 0;
25287 }
25288
25289 DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */
25290 cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
25291 return (duk_codepoint_t) cp;
25292}
25293#line 1 "duk_api_time.c"
25294/*
25295 * Date/time.
25296 */
25297
25298/* #include duk_internal.h -> already included */
25299
25300DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
25301 /* ECMAScript time, with millisecond fractions. Exposed via
25302 * duk_get_now() for example.
25303 */
25304 DUK_UNREF(thr);
25305 return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
25306}
25307
25308DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
25309 /* ECMAScript time without millisecond fractions. Exposed via
25310 * the Date built-in which doesn't allow fractions.
25311 */
25312 DUK_UNREF(thr);
25313 return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
25314}
25315
25316DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
25317 DUK_UNREF(thr);
25318#if defined(DUK_USE_GET_MONOTONIC_TIME)
25319 return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
25320#else
25321 return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
25322#endif
25323}
25324
25325DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
25326 DUK_ASSERT_API_ENTRY(thr);
25327 DUK_UNREF(thr);
25328
25329 /* This API intentionally allows millisecond fractions. */
25330 return duk_time_get_ecmascript_time(thr);
25331}
25332
25333#if 0 /* XXX: worth exposing? */
25334DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
25335 DUK_ASSERT_API_ENTRY(thr);
25336 DUK_UNREF(thr);
25337
25338 return duk_time_get_monotonic_time(thr);
25339}
25340#endif
25341
25342DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
25343 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
25344 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
25345 duk_uint_t flags;
25346
25347 DUK_ASSERT_API_ENTRY(thr);
25348 DUK_ASSERT(comp != NULL); /* XXX: or check? */
25349 DUK_UNREF(thr);
25350
25351 /* Convert as one-based, but change month to zero-based to match the
25352 * ECMAScript Date built-in behavior 1:1.
25353 */
25354 flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
25355
25356 duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
25357
25358 /* XXX: sub-millisecond accuracy for the API */
25359
25360 DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
25361 comp->year = dparts[DUK_DATE_IDX_YEAR];
25362 comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
25363 comp->day = dparts[DUK_DATE_IDX_DAY];
25364 comp->hours = dparts[DUK_DATE_IDX_HOUR];
25365 comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
25366 comp->seconds = dparts[DUK_DATE_IDX_SECOND];
25367 comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
25368 comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
25369}
25370
25371DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
25372 duk_double_t d;
25373 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
25374 duk_uint_t flags;
25375
25376 DUK_ASSERT_API_ENTRY(thr);
25377 DUK_ASSERT(comp != NULL); /* XXX: or check? */
25378 DUK_UNREF(thr);
25379
25380 /* Match Date constructor behavior (with UTC time). Month is given
25381 * as zero-based. Day-of-month is given as one-based so normalize
25382 * it to zero-based as the internal conversion helpers expects all
25383 * components to be zero-based.
25384 */
25385 flags = 0;
25386
25387 /* XXX: expensive conversion; use array format in API instead, or unify
25388 * time provider and time API to use same struct?
25389 */
25390
25391 dparts[DUK_DATE_IDX_YEAR] = comp->year;
25392 dparts[DUK_DATE_IDX_MONTH] = comp->month;
25393 dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
25394 dparts[DUK_DATE_IDX_HOUR] = comp->hours;
25395 dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
25396 dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
25397 dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
25398 dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
25399
25400 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
25401
25402 return d;
25403}
25404#line 1 "duk_bi_array.c"
25405/*
25406 * Array built-ins
25407 *
25408 * Most Array built-ins are intentionally generic in ECMAScript, and are
25409 * intended to work even when the 'this' binding is not an Array instance.
25410 * This ECMAScript feature is also used by much real world code. For this
25411 * reason the implementations here don't assume exotic Array behavior or
25412 * e.g. presence of a .length property. However, some algorithms have a
25413 * fast path for duk_harray backed actual Array instances, enabled when
25414 * footprint is not a concern.
25415 *
25416 * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
25417 * [[Delete]] operations, but it's currently false throughout. Go through
25418 * all put/delete cases and check throw flag use. Need a new API primitive
25419 * which allows throws flag to be specified.
25420 *
25421 * XXX: array lengths above 2G won't work reliably. There are many places
25422 * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
25423 * i.e. -33- bits). Although array 'length' cannot be written to be outside
25424 * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
25425 * some intermediate values may be above 0xffffffff and this may not be always
25426 * correctly handled now (duk_uint32_t is not enough for all algorithms).
25427 * For instance, push() can legitimately write entries beyond length 0xffffffff
25428 * and cause a RangeError only at the end. To do this properly, the current
25429 * push() implementation tracks the array index using a 'double' instead of a
25430 * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js.
25431 *
25432 * On using "put" vs. "def" prop
25433 * =============================
25434 *
25435 * Code below must be careful to use the appropriate primitive as it matters
25436 * for compliance. When using "put" there may be inherited properties in
25437 * Array.prototype which cause side effects when values are written. When
25438 * using "define" there are no such side effects, and many test262 test cases
25439 * check for this (for real world code, such side effects are very rare).
25440 * Both "put" and "define" are used in the E5.1 specification; as a rule,
25441 * "put" is used when modifying an existing array (or a non-array 'this'
25442 * binding) and "define" for setting values into a fresh result array.
25443 */
25444
25445/* #include duk_internal.h -> already included */
25446
25447/* Perform an intermediate join when this many elements have been pushed
25448 * on the value stack.
25449 */
25450#define DUK__ARRAY_MID_JOIN_LIMIT 4096
25451
25452#if defined(DUK_USE_ARRAY_BUILTIN)
25453
25454/*
25455 * Shared helpers.
25456 */
25457
25458/* Shared entry code for many Array built-ins: the 'this' binding is pushed
25459 * on the value stack and object coerced, and the current .length is returned.
25460 * Note that length is left on stack (it could be popped, but that's not
25461 * usually necessary because call handling will clean it up automatically).
25462 */
25463DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) {
25464 duk_uint32_t len;
25465
25466 /* XXX: push more directly? */
25467 (void) duk_push_this_coercible_to_object(thr);
25468 DUK_HOBJECT_ASSERT_VALID(duk_get_hobject(thr, -1));
25469 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH);
25470 len = duk_to_uint32(thr, -1);
25471
25472 /* -> [ ... ToObject(this) ToUint32(length) ] */
25473 return len;
25474}
25475
25476DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
25477 /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
25478 * represented with duk_int32_t. Use this when the method doesn't
25479 * handle the full 32-bit unsigned range correctly.
25480 */
25481 duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
25482 if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
25483 DUK_ERROR_RANGE_INVALID_LENGTH(thr);
25484 DUK_WO_NORETURN(return 0U;);
25485 }
25486 return ret;
25487}
25488
25489#if defined(DUK_USE_ARRAY_FASTPATH)
25490/* Check if 'this' binding is an Array instance (duk_harray) which satisfies
25491 * a few other guarantees for fast path operation. The fast path doesn't
25492 * need to handle all operations, even for duk_harrays, but must handle a
25493 * significant fraction to improve performance. Return a non-NULL duk_harray
25494 * pointer when all fast path criteria are met, NULL otherwise.
25495 */
25496DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) {
25497 duk_tval *tv;
25498 duk_hobject *h;
25499 duk_uint_t flags_mask, flags_bits, flags_value;
25500
25501 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */
25502 tv = DUK_GET_THIS_TVAL_PTR(thr);
25503
25504 /* Fast path requires that 'this' is a duk_harray. Read only arrays
25505 * (ROM backed) are also rejected for simplicity.
25506 */
25507 if (!DUK_TVAL_IS_OBJECT(tv)) {
25508 DUK_DD(DUK_DDPRINT("reject array fast path: not an object"));
25509 return NULL;
25510 }
25511 h = DUK_TVAL_GET_OBJECT(tv);
25512 DUK_ASSERT(h != NULL);
25513 flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \
25514 DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
25515 DUK_HEAPHDR_FLAG_READONLY;
25516 flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \
25517 DUK_HOBJECT_FLAG_EXOTIC_ARRAY;
25518 flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h);
25519 if ((flags_value & flags_mask) != flags_bits) {
25520 DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed"));
25521 return NULL;
25522 }
25523
25524 /* In some cases a duk_harray's 'length' may be larger than the
25525 * current array part allocation. Avoid the fast path in these
25526 * cases, so that all fast path code can safely assume that all
25527 * items in the range [0,length[ are backed by the current array
25528 * part allocation.
25529 */
25530 if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) {
25531 DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size"));
25532 return NULL;
25533 }
25534
25535 /* Guarantees for fast path. */
25536 DUK_ASSERT(h != NULL);
25537 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL);
25538 DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h));
25539
25540 DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h));
25541 return (duk_harray *) h;
25542}
25543#endif /* DUK_USE_ARRAY_FASTPATH */
25544
25545/*
25546 * Constructor
25547 */
25548
25549DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) {
25550 duk_idx_t nargs;
25551 duk_harray *a;
25552 duk_double_t d;
25553 duk_uint32_t len;
25554 duk_uint32_t len_prealloc;
25555
25556 nargs = duk_get_top(thr);
25557
25558 if (nargs == 1 && duk_is_number(thr, 0)) {
25559 /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
25560 d = duk_get_number(thr, 0);
25561 len = duk_to_uint32(thr, 0);
25562 if (!duk_double_equals((duk_double_t) len, d)) {
25563 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
25564 }
25565
25566 /* For small lengths create a dense preallocated array.
25567 * For large arrays preallocate an initial part.
25568 */
25569 len_prealloc = len < 64 ? len : 64;
25570 a = duk_push_harray_with_size(thr, len_prealloc);
25571 DUK_ASSERT(a != NULL);
25572 DUK_ASSERT(!duk_is_bare_object(thr, -1));
25573 a->length = len;
25574 return 1;
25575 }
25576
25577 duk_pack(thr, nargs);
25578 return 1;
25579}
25580
25581/*
25582 * isArray()
25583 */
25584
25585DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) {
25586 DUK_ASSERT_TOP(thr, 1);
25587 duk_push_boolean(thr, duk_js_isarray(DUK_GET_TVAL_POSIDX(thr, 0)));
25588 return 1;
25589}
25590
25591/*
25592 * toString()
25593 */
25594
25595DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
25596 (void) duk_push_this_coercible_to_object(thr);
25597 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN);
25598
25599 /* [ ... this func ] */
25600 if (!duk_is_callable(thr, -1)) {
25601 /* Fall back to the initial (original) Object.toString(). We don't
25602 * currently have pointers to the built-in functions, only the top
25603 * level global objects (like "Array") so this is now done in a bit
25604 * of a hacky manner. It would be cleaner to push the (original)
25605 * function and use duk_call_method().
25606 */
25607
25608 /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
25609 * but should have no visible side effects.
25610 */
25611 DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
25612 duk_set_top(thr, 0);
25613 return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */
25614 }
25615
25616 /* [ ... this func ] */
25617
25618 duk_insert(thr, -2);
25619
25620 /* [ ... func this ] */
25621
25622 DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
25623 (duk_tval *) duk_get_tval(thr, -2),
25624 (duk_tval *) duk_get_tval(thr, -1)));
25625 duk_call_method(thr, 0);
25626
25627 return 1;
25628}
25629
25630/*
25631 * concat()
25632 */
25633
25634DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
25635 duk_idx_t i, n;
25636 duk_uint32_t j, idx, len;
25637 duk_hobject *h;
25638 duk_size_t tmp_len;
25639
25640 /* XXX: In ES2015 Array .length can be up to 2^53-1. The current
25641 * implementation is limited to 2^32-1.
25642 */
25643
25644 /* XXX: Fast path for array 'this' and array element. */
25645
25646 /* XXX: The insert here is a bit expensive if there are a lot of items.
25647 * It could also be special cased in the outermost for loop quite easily
25648 * (as the element is dup()'d anyway).
25649 */
25650
25651 (void) duk_push_this_coercible_to_object(thr);
25652 duk_insert(thr, 0);
25653 n = duk_get_top(thr);
25654 duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */
25655
25656 /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
25657 * (which differs from the official algorithm). If no error is thrown, this
25658 * doesn't matter as the length is updated at the end. However, if an error
25659 * is thrown, the length will be unset. That shouldn't matter because the
25660 * caller won't get a reference to the intermediate value.
25661 */
25662
25663 idx = 0;
25664 for (i = 0; i < n; i++) {
25665 duk_bool_t spreadable;
25666 duk_bool_t need_has_check;
25667
25668 DUK_ASSERT_TOP(thr, n + 1);
25669
25670 /* [ ToObject(this) item1 ... itemN arr ] */
25671
25672 h = duk_get_hobject(thr, i);
25673
25674 if (h == NULL) {
25675 spreadable = 0;
25676 } else {
25677#if defined(DUK_USE_SYMBOL_BUILTIN)
25678 duk_get_prop_stridx(thr, i, DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE);
25679 if (duk_is_undefined(thr, -1)) {
25680 spreadable = duk_js_isarray_hobject(h);
25681 } else {
25682 spreadable = duk_to_boolean(thr, -1);
25683 }
25684 duk_pop_nodecref_unsafe(thr);
25685#else
25686 spreadable = duk_js_isarray_hobject(h);
25687#endif
25688 }
25689
25690 if (!spreadable) {
25691 duk_dup(thr, i);
25692 duk_xdef_prop_index_wec(thr, -2, idx);
25693 idx++;
25694 if (DUK_UNLIKELY(idx == 0U)) {
25695 /* Index after update is 0, and index written
25696 * was 0xffffffffUL which is no longer a valid
25697 * array index.
25698 */
25699 goto fail_wrap;
25700 }
25701 continue;
25702 }
25703
25704 DUK_ASSERT(duk_is_object(thr, i));
25705 need_has_check = (DUK_HOBJECT_IS_PROXY(h) != 0); /* Always 0 w/o Proxy support. */
25706
25707 /* [ ToObject(this) item1 ... itemN arr ] */
25708
25709 tmp_len = duk_get_length(thr, i);
25710 len = (duk_uint32_t) tmp_len;
25711 if (DUK_UNLIKELY(tmp_len != (duk_size_t) len)) {
25712 goto fail_wrap;
25713 }
25714 if (DUK_UNLIKELY(idx + len < idx)) {
25715 /* Result length must be at most 0xffffffffUL to be
25716 * a valid 32-bit array index.
25717 */
25718 goto fail_wrap;
25719 }
25720 for (j = 0; j < len; j++) {
25721 /* For a Proxy element, an explicit 'has' check is
25722 * needed to allow the Proxy to present gaps.
25723 */
25724 if (need_has_check) {
25725 if (duk_has_prop_index(thr, i, j)) {
25726 duk_get_prop_index(thr, i, j);
25727 duk_xdef_prop_index_wec(thr, -2, idx);
25728 }
25729 } else {
25730 if (duk_get_prop_index(thr, i, j)) {
25731 duk_xdef_prop_index_wec(thr, -2, idx);
25732 } else {
25733 duk_pop_undefined(thr);
25734 }
25735 }
25736 idx++;
25737 DUK_ASSERT(idx != 0U); /* Wrap check above. */
25738 }
25739 }
25740
25741 /* ES5.1 has a specification "bug" in that nonexistent trailing
25742 * elements don't affect the result .length. Test262 and other
25743 * engines disagree, and the specification bug was fixed in ES2015
25744 * (see NOTE 1 in https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat).
25745 */
25746 duk_push_uarridx(thr, idx);
25747 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
25748
25749 DUK_ASSERT_TOP(thr, n + 1);
25750 return 1;
25751
25752 fail_wrap:
25753 DUK_ERROR_RANGE_INVALID_LENGTH(thr);
25754 DUK_WO_NORETURN(return 0;);
25755}
25756
25757/*
25758 * join(), toLocaleString()
25759 *
25760 * Note: checking valstack is necessary, but only in the per-element loop.
25761 *
25762 * Note: the trivial approach of pushing all the elements on the value stack
25763 * and then calling duk_join() fails when the array contains a large number
25764 * of elements. This problem can't be offloaded to duk_join() because the
25765 * elements to join must be handled here and have special handling. Current
25766 * approach is to do intermediate joins with very large number of elements.
25767 * There is no fancy handling; the prefix gets re-joined multiple times.
25768 */
25769
25770DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) {
25771 duk_uint32_t len, count;
25772 duk_uint32_t idx;
25773 duk_small_int_t to_locale_string = duk_get_current_magic(thr);
25774 duk_idx_t valstack_required;
25775
25776 /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
25777 * setting the top essentially pushes an undefined to the stack,
25778 * thus defaulting to a comma separator.
25779 */
25780 duk_set_top(thr, 1);
25781 if (duk_is_undefined(thr, 0)) {
25782 duk_pop_undefined(thr);
25783 duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA);
25784 } else {
25785 duk_to_string(thr, 0);
25786 }
25787
25788 len = duk__push_this_obj_len_u32(thr);
25789
25790 /* [ sep ToObject(this) len ] */
25791
25792 DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
25793 (duk_tval *) duk_get_tval(thr, 0),
25794 (duk_tval *) duk_get_tval(thr, 1),
25795 (unsigned long) len));
25796
25797 /* The extra (+4) is tight. */
25798 valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ?
25799 DUK__ARRAY_MID_JOIN_LIMIT : len) + 4);
25800 duk_require_stack(thr, valstack_required);
25801
25802 duk_dup_0(thr);
25803
25804 /* [ sep ToObject(this) len sep ] */
25805
25806 count = 0;
25807 idx = 0;
25808 for (;;) {
25809 DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx));
25810 if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
25811 idx >= len) { /* end of loop (careful with len==0) */
25812 /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
25813 DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
25814 (long) count, (long) idx, (long) len));
25815 duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
25816 duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */
25817 duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */
25818 count = 1;
25819 }
25820 if (idx >= len) {
25821 /* if true, the stack already contains the final result */
25822 break;
25823 }
25824
25825 duk_get_prop_index(thr, 1, (duk_uarridx_t) idx);
25826 if (duk_is_null_or_undefined(thr, -1)) {
25827 duk_pop_nodecref_unsafe(thr);
25828 duk_push_hstring_empty(thr);
25829 } else {
25830 if (to_locale_string) {
25831 duk_to_object(thr, -1);
25832 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING);
25833 duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */
25834 duk_call_method(thr, 0);
25835 }
25836 duk_to_string(thr, -1);
25837 }
25838
25839 count++;
25840 idx++;
25841 }
25842
25843 /* [ sep ToObject(this) len sep result ] */
25844
25845 return 1;
25846}
25847
25848/*
25849 * pop(), push()
25850 */
25851
25852#if defined(DUK_USE_ARRAY_FASTPATH)
25853DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) {
25854 duk_tval *tv_arraypart;
25855 duk_tval *tv_val;
25856 duk_uint32_t len;
25857
25858 tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
25859 len = h_arr->length;
25860 if (len <= 0) {
25861 /* nop, return undefined */
25862 return 0;
25863 }
25864
25865 len--;
25866 h_arr->length = len;
25867
25868 /* Fast path doesn't check for an index property inherited from
25869 * Array.prototype. This is quite often acceptable; if not,
25870 * disable fast path.
25871 */
25872 DUK_ASSERT_VS_SPACE(thr);
25873 tv_val = tv_arraypart + len;
25874 if (DUK_TVAL_IS_UNUSED(tv_val)) {
25875 /* No net refcount change. Value stack already has
25876 * 'undefined' based on value stack init policy.
25877 */
25878 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
25879 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val));
25880 } else {
25881 /* No net refcount change. */
25882 DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val);
25883 DUK_TVAL_SET_UNUSED(tv_val);
25884 }
25885 thr->valstack_top++;
25886
25887 /* XXX: there's no shrink check in the fast path now */
25888
25889 return 1;
25890}
25891#endif /* DUK_USE_ARRAY_FASTPATH */
25892
25893DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) {
25894 duk_uint32_t len;
25895 duk_uint32_t idx;
25896#if defined(DUK_USE_ARRAY_FASTPATH)
25897 duk_harray *h_arr;
25898#endif
25899
25900 DUK_ASSERT_TOP(thr, 0);
25901
25902#if defined(DUK_USE_ARRAY_FASTPATH)
25903 h_arr = duk__arraypart_fastpath_this(thr);
25904 if (h_arr) {
25905 return duk__array_pop_fastpath(thr, h_arr);
25906 }
25907#endif
25908
25909 /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
25910
25911 len = duk__push_this_obj_len_u32(thr);
25912 if (len == 0) {
25913 duk_push_int(thr, 0);
25914 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
25915 return 0;
25916 }
25917 idx = len - 1;
25918
25919 duk_get_prop_index(thr, 0, (duk_uarridx_t) idx);
25920 duk_del_prop_index(thr, 0, (duk_uarridx_t) idx);
25921 duk_push_u32(thr, idx);
25922 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
25923 return 1;
25924}
25925
25926#if defined(DUK_USE_ARRAY_FASTPATH)
25927DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) {
25928 duk_tval *tv_arraypart;
25929 duk_tval *tv_src;
25930 duk_tval *tv_dst;
25931 duk_uint32_t len;
25932 duk_idx_t i, n;
25933
25934 len = h_arr->length;
25935 tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
25936
25937 n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
25938 DUK_ASSERT(n >= 0);
25939 DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX);
25940 if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) {
25941 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
25942 DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */
25943 }
25944 if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
25945 /* Array part would need to be extended. Rely on slow path
25946 * for now.
25947 *
25948 * XXX: Rework hobject code a bit and add extend support.
25949 */
25950 return 0;
25951 }
25952
25953 tv_src = thr->valstack_bottom;
25954 tv_dst = tv_arraypart + len;
25955 for (i = 0; i < n; i++) {
25956 /* No net refcount change; reset value stack values to
25957 * undefined to satisfy value stack init policy.
25958 */
25959 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
25960 DUK_TVAL_SET_UNDEFINED(tv_src);
25961 tv_src++;
25962 tv_dst++;
25963 }
25964 thr->valstack_top = thr->valstack_bottom;
25965 len += (duk_uint32_t) n;
25966 h_arr->length = len;
25967
25968 DUK_ASSERT((duk_uint_t) len == len);
25969 duk_push_uint(thr, (duk_uint_t) len);
25970 return 1;
25971}
25972#endif /* DUK_USE_ARRAY_FASTPATH */
25973
25974DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) {
25975 /* Note: 'this' is not necessarily an Array object. The push()
25976 * algorithm is supposed to work for other kinds of objects too,
25977 * so the algorithm has e.g. an explicit update for the 'length'
25978 * property which is normally "magical" in arrays.
25979 */
25980
25981 duk_uint32_t len;
25982 duk_idx_t i, n;
25983#if defined(DUK_USE_ARRAY_FASTPATH)
25984 duk_harray *h_arr;
25985#endif
25986
25987#if defined(DUK_USE_ARRAY_FASTPATH)
25988 h_arr = duk__arraypart_fastpath_this(thr);
25989 if (h_arr) {
25990 duk_ret_t rc;
25991 rc = duk__array_push_fastpath(thr, h_arr);
25992 if (rc != 0) {
25993 return rc;
25994 }
25995 DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case"));
25996 }
25997#endif
25998
25999 n = duk_get_top(thr);
26000 len = duk__push_this_obj_len_u32(thr);
26001
26002 /* [ arg1 ... argN obj length ] */
26003
26004 /* Technically Array.prototype.push() can create an Array with length
26005 * longer than 2^32-1, i.e. outside the 32-bit range. The final length
26006 * is *not* wrapped to 32 bits in the specification.
26007 *
26008 * This implementation tracks length with a uint32 because it's much
26009 * more practical.
26010 *
26011 * See: test-bi-array-push-maxlen.js.
26012 */
26013
26014 if (len + (duk_uint32_t) n < len) {
26015 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
26016 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
26017 }
26018
26019 for (i = 0; i < n; i++) {
26020 duk_dup(thr, i);
26021 duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i));
26022 }
26023 len += (duk_uint32_t) n;
26024
26025 duk_push_u32(thr, len);
26026 duk_dup_top(thr);
26027 duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
26028
26029 /* [ arg1 ... argN obj length new_length ] */
26030 return 1;
26031}
26032
26033/*
26034 * sort()
26035 *
26036 * Currently qsort with random pivot. This is now really, really slow,
26037 * because there is no fast path for array parts.
26038 *
26039 * Signed indices are used because qsort() leaves and degenerate cases
26040 * may use a negative offset.
26041 */
26042
26043DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) {
26044 duk_bool_t have1, have2;
26045 duk_bool_t undef1, undef2;
26046 duk_small_int_t ret;
26047 duk_idx_t idx_obj = 1; /* fixed offsets in valstack */
26048 duk_idx_t idx_fn = 0;
26049 duk_hstring *h1, *h2;
26050
26051 /* Fast exit if indices are identical. This is valid for a non-existent property,
26052 * for an undefined value, and almost always for ToString() coerced comparison of
26053 * arbitrary values (corner cases where this is not the case include e.g. a an
26054 * object with varying ToString() coercion).
26055 *
26056 * The specification does not prohibit "caching" of values read from the array, so
26057 * assuming equality for comparing an index with itself falls into the category of
26058 * "caching".
26059 *
26060 * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
26061 * have an effect on the final result. The specification does not require any
26062 * specific behavior for inconsistent compare functions, so again, this fast path
26063 * is OK.
26064 */
26065
26066 if (idx1 == idx2) {
26067 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
26068 (long) idx1, (long) idx2));
26069 return 0;
26070 }
26071
26072 have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1);
26073 have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2);
26074
26075 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
26076 (long) idx1, (long) idx2, (long) have1, (long) have2,
26077 (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
26078
26079 if (have1) {
26080 if (have2) {
26081 ;
26082 } else {
26083 ret = -1;
26084 goto pop_ret;
26085 }
26086 } else {
26087 if (have2) {
26088 ret = 1;
26089 goto pop_ret;
26090 } else {
26091 ret = 0;
26092 goto pop_ret;
26093 }
26094 }
26095
26096 undef1 = duk_is_undefined(thr, -2);
26097 undef2 = duk_is_undefined(thr, -1);
26098 if (undef1) {
26099 if (undef2) {
26100 ret = 0;
26101 goto pop_ret;
26102 } else {
26103 ret = 1;
26104 goto pop_ret;
26105 }
26106 } else {
26107 if (undef2) {
26108 ret = -1;
26109 goto pop_ret;
26110 } else {
26111 ;
26112 }
26113 }
26114
26115 if (!duk_is_undefined(thr, idx_fn)) {
26116 duk_double_t d;
26117
26118 /* No need to check callable; duk_call() will do that. */
26119 duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */
26120 duk_insert(thr, -3); /* -> [ ... fn x y ] */
26121 duk_call(thr, 2); /* -> [ ... res ] */
26122
26123 /* ES5 is a bit vague about what to do if the return value is
26124 * not a number. ES2015 provides a concrete description:
26125 * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
26126 */
26127
26128 d = duk_to_number_m1(thr);
26129 if (d < 0.0) {
26130 ret = -1;
26131 } else if (d > 0.0) {
26132 ret = 1;
26133 } else {
26134 /* Because NaN compares to false, NaN is handled here
26135 * without an explicit check above.
26136 */
26137 ret = 0;
26138 }
26139
26140 duk_pop_nodecref_unsafe(thr);
26141 DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
26142 return ret;
26143 }
26144
26145 /* string compare is the default (a bit oddly) */
26146
26147 /* XXX: any special handling for plain array; causes repeated coercion now? */
26148 h1 = duk_to_hstring(thr, -2);
26149 h2 = duk_to_hstring_m1(thr);
26150 DUK_ASSERT(h1 != NULL);
26151 DUK_ASSERT(h2 != NULL);
26152
26153 ret = duk_js_string_compare(h1, h2); /* retval is directly usable */
26154 goto pop_ret;
26155
26156 pop_ret:
26157 duk_pop_2_unsafe(thr);
26158 DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
26159 return ret;
26160}
26161
26162DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) {
26163 duk_bool_t have_l, have_r;
26164 duk_idx_t idx_obj = 1; /* fixed offset in valstack */
26165
26166 if (l == r) {
26167 return;
26168 }
26169
26170 /* swap elements; deal with non-existent elements correctly */
26171 have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l);
26172 have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r);
26173
26174 if (have_r) {
26175 /* right exists, [[Put]] regardless whether or not left exists */
26176 duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l);
26177 } else {
26178 duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l);
26179 duk_pop_undefined(thr);
26180 }
26181
26182 if (have_l) {
26183 duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r);
26184 } else {
26185 duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r);
26186 duk_pop_undefined(thr);
26187 }
26188}
26189
26190#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
26191/* Debug print which visualizes the qsort partitioning process. */
26192DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
26193 char buf[4096];
26194 char *ptr = buf;
26195 duk_int_t i, n;
26196 n = (duk_int_t) duk_get_length(thr, 1);
26197 if (n > 4000) {
26198 n = 4000;
26199 }
26200 *ptr++ = '[';
26201 for (i = 0; i < n; i++) {
26202 if (i == pivot) {
26203 *ptr++ = '|';
26204 } else if (i == lo) {
26205 *ptr++ = '<';
26206 } else if (i == hi) {
26207 *ptr++ = '>';
26208 } else if (i >= lo && i <= hi) {
26209 *ptr++ = '-';
26210 } else {
26211 *ptr++ = ' ';
26212 }
26213 }
26214 *ptr++ = ']';
26215 *ptr++ = '\0';
26216
26217 DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)",
26218 (const char *) buf, (long) lo, (long) hi, (long) pivot));
26219}
26220#endif
26221
26222DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) {
26223 duk_int_t p, l, r;
26224
26225 /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
26226
26227 DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
26228 (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1)));
26229
26230 DUK_ASSERT_TOP(thr, 3);
26231
26232 /* In some cases it may be that lo > hi, or hi < 0; these
26233 * degenerate cases happen e.g. for empty arrays, and in
26234 * recursion leaves.
26235 */
26236
26237 /* trivial cases */
26238 if (hi - lo < 1) {
26239 DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
26240 return;
26241 }
26242 DUK_ASSERT(hi > lo);
26243 DUK_ASSERT(hi - lo + 1 >= 2);
26244
26245 /* randomized pivot selection */
26246 p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1));
26247 DUK_ASSERT(p >= lo && p <= hi);
26248 DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
26249
26250 /* move pivot out of the way */
26251 duk__array_sort_swap(thr, p, lo);
26252 p = lo;
26253 DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1)));
26254
26255 l = lo + 1;
26256 r = hi;
26257 for (;;) {
26258 /* find elements to swap */
26259 for (;;) {
26260 DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
26261 (long) l, (long) r, (long) p));
26262 if (l >= hi) {
26263 break;
26264 }
26265 if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */
26266 break;
26267 }
26268 l++;
26269 }
26270 for (;;) {
26271 DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
26272 (long) l, (long) r, (long) p));
26273 if (r <= lo) {
26274 break;
26275 }
26276 if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */
26277 break;
26278 }
26279 r--;
26280 }
26281 if (l >= r) {
26282 goto done;
26283 }
26284 DUK_ASSERT(l < r);
26285
26286 DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
26287
26288 duk__array_sort_swap(thr, l, r);
26289
26290 DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
26291 l++;
26292 r--;
26293 }
26294 done:
26295 /* Note that 'l' and 'r' may cross, i.e. r < l */
26296 DUK_ASSERT(l >= lo && l <= hi);
26297 DUK_ASSERT(r >= lo && r <= hi);
26298
26299 /* XXX: there's no explicit recursion bound here now. For the average
26300 * qsort recursion depth O(log n) that's not really necessary: e.g. for
26301 * 2**32 recursion depth would be about 32 which is OK. However, qsort
26302 * worst case recursion depth is O(n) which may be a problem.
26303 */
26304
26305 /* move pivot to its final place */
26306 DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
26307 duk__array_sort_swap(thr, lo, r);
26308
26309#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
26310 duk__debuglog_qsort_state(thr, lo, hi, r);
26311#endif
26312
26313 DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1)));
26314 duk__array_qsort(thr, lo, r - 1);
26315 duk__array_qsort(thr, r + 1, hi);
26316}
26317
26318DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) {
26319 duk_uint32_t len;
26320
26321 /* XXX: len >= 0x80000000 won't work below because a signed type
26322 * is needed by qsort.
26323 */
26324 len = duk__push_this_obj_len_u32_limited(thr);
26325
26326 /* stack[0] = compareFn
26327 * stack[1] = ToObject(this)
26328 * stack[2] = ToUint32(length)
26329 */
26330
26331 if (len > 0) {
26332 /* avoid degenerate cases, so that (len - 1) won't underflow */
26333 duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1));
26334 }
26335
26336 DUK_ASSERT_TOP(thr, 3);
26337 duk_pop_nodecref_unsafe(thr);
26338 return 1; /* return ToObject(this) */
26339}
26340
26341/*
26342 * splice()
26343 */
26344
26345/* XXX: this compiles to over 500 bytes now, even without special handling
26346 * for an array part. Uses signed ints so does not handle full array range correctly.
26347 */
26348
26349/* XXX: can shift() / unshift() use the same helper?
26350 * shift() is (close to?) <--> splice(0, 1)
26351 * unshift is (close to?) <--> splice(0, 0, [items])?
26352 */
26353
26354DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) {
26355 duk_idx_t nargs;
26356 duk_uint32_t len_u32;
26357 duk_int_t len;
26358 duk_bool_t have_delcount;
26359 duk_int_t item_count;
26360 duk_int_t act_start;
26361 duk_int_t del_count;
26362 duk_int_t i, n;
26363
26364 DUK_UNREF(have_delcount);
26365
26366 nargs = duk_get_top(thr);
26367 if (nargs < 2) {
26368 duk_set_top(thr, 2);
26369 nargs = 2;
26370 have_delcount = 0;
26371 } else {
26372 have_delcount = 1;
26373 }
26374
26375 /* XXX: len >= 0x80000000 won't work below because we need to be
26376 * able to represent -len.
26377 */
26378 len_u32 = duk__push_this_obj_len_u32_limited(thr);
26379 len = (duk_int_t) len_u32;
26380 DUK_ASSERT(len >= 0);
26381
26382 act_start = duk_to_int_clamped(thr, 0, -len, len);
26383 if (act_start < 0) {
26384 act_start = len + act_start;
26385 }
26386 DUK_ASSERT(act_start >= 0 && act_start <= len);
26387
26388#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
26389 if (have_delcount) {
26390#endif
26391 del_count = duk_to_int_clamped(thr, 1, 0, len - act_start);
26392#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
26393 } else {
26394 /* E5.1 standard behavior when deleteCount is not given would be
26395 * to treat it just like if 'undefined' was given, which coerces
26396 * ultimately to 0. Real world behavior is to splice to the end
26397 * of array, see test-bi-array-proto-splice-no-delcount.js.
26398 */
26399 del_count = len - act_start;
26400 }
26401#endif
26402
26403 DUK_ASSERT(nargs >= 2);
26404 item_count = (duk_int_t) (nargs - 2);
26405
26406 DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
26407 DUK_ASSERT(del_count + act_start <= len);
26408
26409 /* For now, restrict result array into 32-bit length range. */
26410 if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
26411 DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
26412 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
26413 }
26414
26415 duk_push_array(thr);
26416
26417 /* stack[0] = start
26418 * stack[1] = deleteCount
26419 * stack[2...nargs-1] = items
26420 * stack[nargs] = ToObject(this) -3
26421 * stack[nargs+1] = ToUint32(length) -2
26422 * stack[nargs+2] = result array -1
26423 */
26424
26425 DUK_ASSERT_TOP(thr, nargs + 3);
26426
26427 /* Step 9: copy elements-to-be-deleted into the result array */
26428
26429 for (i = 0; i < del_count; i++) {
26430 if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) {
26431 duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */
26432 } else {
26433 duk_pop_undefined(thr);
26434 }
26435 }
26436 duk_push_u32(thr, (duk_uint32_t) del_count);
26437 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
26438
26439 /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
26440
26441 if (item_count < del_count) {
26442 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
26443 * -> [ A B F G H ] (conceptual intermediate step)
26444 * -> [ A B . F G H ] (placeholder marked)
26445 * [ A B C F G H ] (actual result at this point, C will be replaced)
26446 */
26447
26448 DUK_ASSERT_TOP(thr, nargs + 3);
26449
26450 n = len - del_count;
26451 for (i = act_start; i < n; i++) {
26452 if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
26453 duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
26454 } else {
26455 duk_pop_undefined(thr);
26456 duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
26457 }
26458 }
26459
26460 DUK_ASSERT_TOP(thr, nargs + 3);
26461
26462 /* loop iterator init and limit changed from standard algorithm */
26463 n = len - del_count + item_count;
26464 for (i = len - 1; i >= n; i--) {
26465 duk_del_prop_index(thr, -3, (duk_uarridx_t) i);
26466 }
26467
26468 DUK_ASSERT_TOP(thr, nargs + 3);
26469 } else if (item_count > del_count) {
26470 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
26471 * -> [ A B F G H ] (conceptual intermediate step)
26472 * -> [ A B . . . . F G H ] (placeholder marked)
26473 * [ A B C D E F F G H ] (actual result at this point)
26474 */
26475
26476 DUK_ASSERT_TOP(thr, nargs + 3);
26477
26478 /* loop iterator init and limit changed from standard algorithm */
26479 for (i = len - del_count - 1; i >= act_start; i--) {
26480 if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
26481 duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
26482 } else {
26483 duk_pop_undefined(thr);
26484 duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
26485 }
26486 }
26487
26488 DUK_ASSERT_TOP(thr, nargs + 3);
26489 } else {
26490 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
26491 * -> [ A B F G H ] (conceptual intermediate step)
26492 * -> [ A B . . . F G H ] (placeholder marked)
26493 * [ A B C D E F G H ] (actual result at this point)
26494 */
26495 }
26496 DUK_ASSERT_TOP(thr, nargs + 3);
26497
26498 /* Step 15: insert itemCount elements into the hole made above */
26499
26500 for (i = 0; i < item_count; i++) {
26501 duk_dup(thr, i + 2); /* args start at index 2 */
26502 duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i));
26503 }
26504
26505 /* Step 16: update length; note that the final length may be above 32 bit range
26506 * (but we checked above that this isn't the case here)
26507 */
26508
26509 duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count));
26510 duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
26511
26512 /* result array is already at the top of stack */
26513 DUK_ASSERT_TOP(thr, nargs + 3);
26514 return 1;
26515}
26516
26517/*
26518 * reverse()
26519 */
26520
26521DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) {
26522 duk_uint32_t len;
26523 duk_uint32_t middle;
26524 duk_uint32_t lower, upper;
26525 duk_bool_t have_lower, have_upper;
26526
26527 len = duk__push_this_obj_len_u32(thr);
26528 middle = len / 2;
26529
26530 /* If len <= 1, middle will be 0 and for-loop bails out
26531 * immediately (0 < 0 -> false).
26532 */
26533
26534 for (lower = 0; lower < middle; lower++) {
26535 DUK_ASSERT(len >= 2);
26536 DUK_ASSERT_TOP(thr, 2);
26537
26538 DUK_ASSERT(len >= lower + 1);
26539 upper = len - lower - 1;
26540
26541 have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower);
26542 have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper);
26543
26544 /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
26545
26546 if (have_upper) {
26547 duk_put_prop_index(thr, -4, (duk_uarridx_t) lower);
26548 } else {
26549 duk_del_prop_index(thr, -4, (duk_uarridx_t) lower);
26550 duk_pop_undefined(thr);
26551 }
26552
26553 if (have_lower) {
26554 duk_put_prop_index(thr, -3, (duk_uarridx_t) upper);
26555 } else {
26556 duk_del_prop_index(thr, -3, (duk_uarridx_t) upper);
26557 duk_pop_undefined(thr);
26558 }
26559
26560 DUK_ASSERT_TOP(thr, 2);
26561 }
26562
26563 DUK_ASSERT_TOP(thr, 2);
26564 duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */
26565 return 1;
26566}
26567
26568/*
26569 * slice()
26570 */
26571
26572DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) {
26573 duk_uint32_t len_u32;
26574 duk_int_t len;
26575 duk_int_t start, end;
26576 duk_int_t i;
26577 duk_uarridx_t idx;
26578 duk_uint32_t res_length = 0;
26579
26580 /* XXX: len >= 0x80000000 won't work below because we need to be
26581 * able to represent -len.
26582 */
26583 len_u32 = duk__push_this_obj_len_u32_limited(thr);
26584 len = (duk_int_t) len_u32;
26585 DUK_ASSERT(len >= 0);
26586
26587 duk_push_array(thr);
26588
26589 /* stack[0] = start
26590 * stack[1] = end
26591 * stack[2] = ToObject(this)
26592 * stack[3] = ToUint32(length)
26593 * stack[4] = result array
26594 */
26595
26596 start = duk_to_int_clamped(thr, 0, -len, len);
26597 if (start < 0) {
26598 start = len + start;
26599 }
26600 /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
26601 * (the upper limit)?
26602 */
26603 if (duk_is_undefined(thr, 1)) {
26604 end = len;
26605 } else {
26606 end = duk_to_int_clamped(thr, 1, -len, len);
26607 if (end < 0) {
26608 end = len + end;
26609 }
26610 }
26611 DUK_ASSERT(start >= 0 && start <= len);
26612 DUK_ASSERT(end >= 0 && end <= len);
26613
26614 idx = 0;
26615 for (i = start; i < end; i++) {
26616 DUK_ASSERT_TOP(thr, 5);
26617 if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26618 duk_xdef_prop_index_wec(thr, 4, idx);
26619 res_length = idx + 1;
26620 } else {
26621 duk_pop_undefined(thr);
26622 }
26623 idx++;
26624 DUK_ASSERT_TOP(thr, 5);
26625 }
26626
26627 duk_push_u32(thr, res_length);
26628 duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
26629
26630 DUK_ASSERT_TOP(thr, 5);
26631 return 1;
26632}
26633
26634/*
26635 * shift()
26636 */
26637
26638DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) {
26639 duk_uint32_t len;
26640 duk_uint32_t i;
26641
26642 len = duk__push_this_obj_len_u32(thr);
26643 if (len == 0) {
26644 duk_push_int(thr, 0);
26645 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
26646 return 0;
26647 }
26648
26649 duk_get_prop_index(thr, 0, 0);
26650
26651 /* stack[0] = object (this)
26652 * stack[1] = ToUint32(length)
26653 * stack[2] = elem at index 0 (retval)
26654 */
26655
26656 for (i = 1; i < len; i++) {
26657 DUK_ASSERT_TOP(thr, 3);
26658 if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) {
26659 /* fromPresent = true */
26660 duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
26661 } else {
26662 /* fromPresent = false */
26663 duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
26664 duk_pop_undefined(thr);
26665 }
26666 }
26667 duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1));
26668
26669 duk_push_u32(thr, (duk_uint32_t) (len - 1));
26670 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
26671
26672 DUK_ASSERT_TOP(thr, 3);
26673 return 1;
26674}
26675
26676/*
26677 * unshift()
26678 */
26679
26680DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) {
26681 duk_idx_t nargs;
26682 duk_uint32_t len;
26683 duk_uint32_t i;
26684
26685 nargs = duk_get_top(thr);
26686 len = duk__push_this_obj_len_u32(thr);
26687
26688 /* stack[0...nargs-1] = unshift args (vararg)
26689 * stack[nargs] = ToObject(this)
26690 * stack[nargs+1] = ToUint32(length)
26691 */
26692
26693 DUK_ASSERT_TOP(thr, nargs + 2);
26694
26695 /* Note: unshift() may operate on indices above unsigned 32-bit range
26696 * and the final length may be >= 2**32. However, we restrict the
26697 * final result to 32-bit range for practicality.
26698 */
26699
26700 if (len + (duk_uint32_t) nargs < len) {
26701 DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
26702 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
26703 }
26704
26705 i = len;
26706 while (i > 0) {
26707 DUK_ASSERT_TOP(thr, nargs + 2);
26708 i--;
26709 /* k+argCount-1; note that may be above 32-bit range */
26710
26711 if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) {
26712 /* fromPresent = true */
26713 /* [ ... ToObject(this) ToUint32(length) val ] */
26714 duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
26715 } else {
26716 /* fromPresent = false */
26717 /* [ ... ToObject(this) ToUint32(length) val ] */
26718 duk_pop_undefined(thr);
26719 duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
26720 }
26721 DUK_ASSERT_TOP(thr, nargs + 2);
26722 }
26723
26724 for (i = 0; i < (duk_uint32_t) nargs; i++) {
26725 DUK_ASSERT_TOP(thr, nargs + 2);
26726 duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
26727 duk_put_prop_index(thr, -3, (duk_uarridx_t) i);
26728 DUK_ASSERT_TOP(thr, nargs + 2);
26729 }
26730
26731 DUK_ASSERT_TOP(thr, nargs + 2);
26732 duk_push_u32(thr, len + (duk_uint32_t) nargs);
26733 duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
26734 duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
26735 return 1;
26736}
26737
26738/*
26739 * indexOf(), lastIndexOf()
26740 */
26741
26742DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) {
26743 duk_idx_t nargs;
26744 duk_int_t i, len;
26745 duk_int_t from_idx;
26746 duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
26747
26748 /* lastIndexOf() needs to be a vararg function because we must distinguish
26749 * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
26750 * made vararg for symmetry although it doesn't strictly need to be.
26751 */
26752
26753 nargs = duk_get_top(thr);
26754 duk_set_top(thr, 2);
26755
26756 /* XXX: must be able to represent -len */
26757 len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr);
26758 if (len == 0) {
26759 goto not_found;
26760 }
26761
26762 /* Index clamping is a bit tricky, we must ensure that we'll only iterate
26763 * through elements that exist and that the specific requirements from E5.1
26764 * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
26765 *
26766 * - indexOf: clamp to [-len,len], negative handling -> [0,len],
26767 * if clamped result is len, for-loop bails out immediately
26768 *
26769 * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
26770 * if clamped result is -1, for-loop bails out immediately
26771 *
26772 * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
26773 * for indexOf() but incorrect for lastIndexOf(). Hence special handling,
26774 * and why lastIndexOf() needs to be a vararg function.
26775 */
26776
26777 if (nargs >= 2) {
26778 /* indexOf: clamp fromIndex to [-len, len]
26779 * (if fromIndex == len, for-loop terminates directly)
26780 *
26781 * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
26782 * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
26783 */
26784 from_idx = duk_to_int_clamped(thr,
26785 1,
26786 (idx_step > 0 ? -len : -len - 1),
26787 (idx_step > 0 ? len : len - 1));
26788 if (from_idx < 0) {
26789 /* for lastIndexOf, result may be -1 (mark immediate termination) */
26790 from_idx = len + from_idx;
26791 }
26792 } else {
26793 /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
26794 * handle both indexOf and lastIndexOf specially here.
26795 */
26796 if (idx_step > 0) {
26797 from_idx = 0;
26798 } else {
26799 from_idx = len - 1;
26800 }
26801 }
26802
26803 /* stack[0] = searchElement
26804 * stack[1] = fromIndex
26805 * stack[2] = object
26806 * stack[3] = length (not needed, but not popped above)
26807 */
26808
26809 for (i = from_idx; i >= 0 && i < len; i += idx_step) {
26810 DUK_ASSERT_TOP(thr, 4);
26811
26812 if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26813 DUK_ASSERT_TOP(thr, 5);
26814 if (duk_strict_equals(thr, 0, 4)) {
26815 duk_push_int(thr, i);
26816 return 1;
26817 }
26818 }
26819
26820 duk_pop_unsafe(thr);
26821 }
26822
26823 not_found:
26824 duk_push_int(thr, -1);
26825 return 1;
26826}
26827
26828/*
26829 * every(), some(), forEach(), map(), filter()
26830 */
26831
26832#define DUK__ITER_EVERY 0
26833#define DUK__ITER_SOME 1
26834#define DUK__ITER_FOREACH 2
26835#define DUK__ITER_MAP 3
26836#define DUK__ITER_FILTER 4
26837
26838/* XXX: This helper is a bit awkward because the handling for the different iteration
26839 * callers is quite different. This now compiles to a bit less than 500 bytes, so with
26840 * 5 callers the net result is about 100 bytes / caller.
26841 */
26842
26843DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
26844 duk_uint32_t len;
26845 duk_uint32_t i;
26846 duk_uarridx_t k;
26847 duk_bool_t bval;
26848 duk_small_int_t iter_type = duk_get_current_magic(thr);
26849 duk_uint32_t res_length = 0;
26850
26851 /* each call this helper serves has nargs==2 */
26852 DUK_ASSERT_TOP(thr, 2);
26853
26854 len = duk__push_this_obj_len_u32(thr);
26855 duk_require_callable(thr, 0);
26856 /* if thisArg not supplied, behave as if undefined was supplied */
26857
26858 if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
26859 duk_push_array(thr);
26860 } else {
26861 duk_push_undefined(thr);
26862 }
26863
26864 /* stack[0] = callback
26865 * stack[1] = thisArg
26866 * stack[2] = object
26867 * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop)
26868 * stack[4] = result array (or undefined)
26869 */
26870
26871 k = 0; /* result index for filter() */
26872 for (i = 0; i < len; i++) {
26873 DUK_ASSERT_TOP(thr, 5);
26874
26875 if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26876 /* For 'map' trailing missing elements don't invoke the
26877 * callback but count towards the result length.
26878 */
26879 if (iter_type == DUK__ITER_MAP) {
26880 res_length = i + 1;
26881 }
26882 duk_pop_undefined(thr);
26883 continue;
26884 }
26885
26886 /* The original value needs to be preserved for filter(), hence
26887 * this funny order. We can't re-get the value because of side
26888 * effects.
26889 */
26890
26891 duk_dup_0(thr);
26892 duk_dup_1(thr);
26893 duk_dup_m3(thr);
26894 duk_push_u32(thr, i);
26895 duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */
26896 duk_call_method(thr, 3); /* -> [ ... val retval ] */
26897
26898 switch (iter_type) {
26899 case DUK__ITER_EVERY:
26900 bval = duk_to_boolean(thr, -1);
26901 if (!bval) {
26902 /* stack top contains 'false' */
26903 return 1;
26904 }
26905 break;
26906 case DUK__ITER_SOME:
26907 bval = duk_to_boolean(thr, -1);
26908 if (bval) {
26909 /* stack top contains 'true' */
26910 return 1;
26911 }
26912 break;
26913 case DUK__ITER_FOREACH:
26914 /* nop */
26915 break;
26916 case DUK__ITER_MAP:
26917 duk_dup_top(thr);
26918 duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */
26919 res_length = i + 1;
26920 break;
26921 case DUK__ITER_FILTER:
26922 bval = duk_to_boolean(thr, -1);
26923 if (bval) {
26924 duk_dup_m2(thr); /* orig value */
26925 duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k);
26926 k++;
26927 res_length = k;
26928 }
26929 break;
26930 default:
26931 DUK_UNREACHABLE();
26932 break;
26933 }
26934 duk_pop_2_unsafe(thr);
26935
26936 DUK_ASSERT_TOP(thr, 5);
26937 }
26938
26939 switch (iter_type) {
26940 case DUK__ITER_EVERY:
26941 duk_push_true(thr);
26942 break;
26943 case DUK__ITER_SOME:
26944 duk_push_false(thr);
26945 break;
26946 case DUK__ITER_FOREACH:
26947 duk_push_undefined(thr);
26948 break;
26949 case DUK__ITER_MAP:
26950 case DUK__ITER_FILTER:
26951 DUK_ASSERT_TOP(thr, 5);
26952 DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */
26953 duk_push_u32(thr, res_length);
26954 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
26955 break;
26956 default:
26957 DUK_UNREACHABLE();
26958 break;
26959 }
26960
26961 return 1;
26962}
26963
26964/*
26965 * reduce(), reduceRight()
26966 */
26967
26968DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) {
26969 duk_idx_t nargs;
26970 duk_bool_t have_acc;
26971 duk_uint32_t i, len;
26972 duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */
26973
26974 /* We're a varargs function because we need to detect whether
26975 * initialValue was given or not.
26976 */
26977 nargs = duk_get_top(thr);
26978 DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
26979
26980 duk_set_top(thr, 2);
26981 len = duk__push_this_obj_len_u32(thr);
26982 duk_require_callable(thr, 0);
26983
26984 /* stack[0] = callback fn
26985 * stack[1] = initialValue
26986 * stack[2] = object (coerced this)
26987 * stack[3] = length (not needed, but not popped above)
26988 * stack[4] = accumulator
26989 */
26990
26991 have_acc = 0;
26992 if (nargs >= 2) {
26993 duk_dup_1(thr);
26994 have_acc = 1;
26995 }
26996 DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
26997 (long) have_acc, (duk_tval *) duk_get_tval(thr, 3)));
26998
26999 /* For len == 0, i is initialized to len - 1 which underflows.
27000 * The condition (i < len) will then exit the for-loop on the
27001 * first round which is correct. Similarly, loop termination
27002 * happens by i underflowing.
27003 */
27004
27005 for (i = (idx_step >= 0 ? 0 : len - 1);
27006 i < len; /* i >= 0 would always be true */
27007 i += (duk_uint32_t) idx_step) {
27008 DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
27009 (long) i, (long) len, (long) have_acc,
27010 (long) duk_get_top(thr),
27011 (duk_tval *) duk_get_tval(thr, 4)));
27012
27013 DUK_ASSERT((have_acc && duk_get_top(thr) == 5) ||
27014 (!have_acc && duk_get_top(thr) == 4));
27015
27016 if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) {
27017 continue;
27018 }
27019
27020 if (!have_acc) {
27021 DUK_ASSERT_TOP(thr, 4);
27022 duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
27023 have_acc = 1;
27024 DUK_ASSERT_TOP(thr, 5);
27025 } else {
27026 DUK_ASSERT_TOP(thr, 5);
27027 duk_dup_0(thr);
27028 duk_dup(thr, 4);
27029 duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
27030 duk_push_u32(thr, i);
27031 duk_dup_2(thr);
27032 DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
27033 (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4),
27034 (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
27035 (duk_tval *) duk_get_tval(thr, -1)));
27036 duk_call(thr, 4);
27037 DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
27038 duk_replace(thr, 4);
27039 DUK_ASSERT_TOP(thr, 5);
27040 }
27041 }
27042
27043 if (!have_acc) {
27044 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27045 }
27046
27047 DUK_ASSERT_TOP(thr, 5);
27048 return 1;
27049}
27050
27051#endif /* DUK_USE_ARRAY_BUILTIN */
27052
27053/* automatic undefs */
27054#undef DUK__ARRAY_MID_JOIN_LIMIT
27055#undef DUK__ITER_EVERY
27056#undef DUK__ITER_FILTER
27057#undef DUK__ITER_FOREACH
27058#undef DUK__ITER_MAP
27059#undef DUK__ITER_SOME
27060#line 1 "duk_bi_boolean.c"
27061/*
27062 * Boolean built-ins
27063 */
27064
27065/* #include duk_internal.h -> already included */
27066
27067#if defined(DUK_USE_BOOLEAN_BUILTIN)
27068
27069/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
27070 * the primitive value to stack top, and optionally coerces with ToString().
27071 */
27072DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
27073 duk_tval *tv;
27074 duk_hobject *h;
27075 duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
27076
27077 /* XXX: there is room to use a shared helper here, many built-ins
27078 * check the 'this' type, and if it's an object, check its class,
27079 * then get its internal value, etc.
27080 */
27081
27082 duk_push_this(thr);
27083 tv = duk_get_tval(thr, -1);
27084 DUK_ASSERT(tv != NULL);
27085
27086 if (DUK_TVAL_IS_BOOLEAN(tv)) {
27087 goto type_ok;
27088 } else if (DUK_TVAL_IS_OBJECT(tv)) {
27089 h = DUK_TVAL_GET_OBJECT(tv);
27090 DUK_ASSERT(h != NULL);
27091
27092 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
27093 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
27094 DUK_ASSERT(duk_is_boolean(thr, -1));
27095 goto type_ok;
27096 }
27097 }
27098
27099 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27100 /* never here */
27101
27102 type_ok:
27103 if (coerce_tostring) {
27104 duk_to_string(thr, -1);
27105 }
27106 return 1;
27107}
27108
27109DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
27110 duk_hobject *h_this;
27111
27112 duk_to_boolean(thr, 0);
27113
27114 if (duk_is_constructor_call(thr)) {
27115 /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
27116 duk_push_this(thr);
27117 h_this = duk_known_hobject(thr, -1);
27118 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
27119
27120 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
27121
27122 duk_dup_0(thr); /* -> [ val obj val ] */
27123 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
27124 } /* unbalanced stack */
27125
27126 return 1;
27127}
27128
27129#endif /* DUK_USE_BOOLEAN_BUILTIN */
27130#line 1 "duk_bi_buffer.c"
27131/*
27132 * ES2015 TypedArray and Node.js Buffer built-ins
27133 */
27134
27135/* #include duk_internal.h -> already included */
27136
27137/*
27138 * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT.
27139 */
27140
27141#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27142/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the
27143 * default internal prototype.
27144 */
27145static const duk_uint8_t duk__buffer_proto_from_classnum[] = {
27146 DUK_BIDX_ARRAYBUFFER_PROTOTYPE,
27147 DUK_BIDX_DATAVIEW_PROTOTYPE,
27148 DUK_BIDX_INT8ARRAY_PROTOTYPE,
27149 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
27150 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
27151 DUK_BIDX_INT16ARRAY_PROTOTYPE,
27152 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
27153 DUK_BIDX_INT32ARRAY_PROTOTYPE,
27154 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
27155 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
27156 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
27157};
27158
27159/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number.
27160 * Sync with duk_hbufobj.h and duk_hobject.h.
27161 */
27162static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
27163 DUK_HOBJECT_CLASS_UINT8ARRAY,
27164 DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
27165 DUK_HOBJECT_CLASS_INT8ARRAY,
27166 DUK_HOBJECT_CLASS_UINT16ARRAY,
27167 DUK_HOBJECT_CLASS_INT16ARRAY,
27168 DUK_HOBJECT_CLASS_UINT32ARRAY,
27169 DUK_HOBJECT_CLASS_INT32ARRAY,
27170 DUK_HOBJECT_CLASS_FLOAT32ARRAY,
27171 DUK_HOBJECT_CLASS_FLOAT64ARRAY
27172};
27173
27174/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index.
27175 * Sync with duk_hbufobj.h.
27176 */
27177static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
27178 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
27179 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
27180 DUK_BIDX_INT8ARRAY_PROTOTYPE,
27181 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
27182 DUK_BIDX_INT16ARRAY_PROTOTYPE,
27183 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
27184 DUK_BIDX_INT32ARRAY_PROTOTYPE,
27185 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
27186 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
27187};
27188
27189/* Map DUK__FLD_xxx to byte size. */
27190static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
27191 1, /* DUK__FLD_8BIT */
27192 2, /* DUK__FLD_16BIT */
27193 4, /* DUK__FLD_32BIT */
27194 4, /* DUK__FLD_FLOAT */
27195 8, /* DUK__FLD_DOUBLE */
27196 0 /* DUK__FLD_VARINT; not relevant here */
27197};
27198
27199/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types
27200 * are compatible with a blind byte copy for the TypedArray set() method (also
27201 * used for TypedArray constructor). Array index is target buffer elem type,
27202 * bitfield indicates compatible source types. The types must have same byte
27203 * size and they must be coercion compatible.
27204 */
27205#if !defined(DUK_USE_PREFER_SIZE)
27206static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
27207 /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */
27208 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
27209 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
27210 (1U << DUK_HBUFOBJ_ELEM_INT8),
27211
27212 /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED
27213 * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
27214 */
27215 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
27216 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED),
27217
27218 /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */
27219 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
27220 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
27221 (1U << DUK_HBUFOBJ_ELEM_INT8),
27222
27223 /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */
27224 (1U << DUK_HBUFOBJ_ELEM_UINT16) |
27225 (1U << DUK_HBUFOBJ_ELEM_INT16),
27226
27227 /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */
27228 (1U << DUK_HBUFOBJ_ELEM_UINT16) |
27229 (1U << DUK_HBUFOBJ_ELEM_INT16),
27230
27231 /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */
27232 (1U << DUK_HBUFOBJ_ELEM_UINT32) |
27233 (1U << DUK_HBUFOBJ_ELEM_INT32),
27234
27235 /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */
27236 (1U << DUK_HBUFOBJ_ELEM_UINT32) |
27237 (1U << DUK_HBUFOBJ_ELEM_INT32),
27238
27239 /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */
27240 (1U << DUK_HBUFOBJ_ELEM_FLOAT32),
27241
27242 /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */
27243 (1U << DUK_HBUFOBJ_ELEM_FLOAT64)
27244};
27245#endif /* !DUK_USE_PREFER_SIZE */
27246
27247DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) {
27248 duk_tval *tv_dst;
27249 duk_hbufobj *res;
27250
27251 duk_push_this(thr);
27252 DUK_ASSERT(duk_is_buffer(thr, -1));
27253 res = (duk_hbufobj *) duk_to_hobject(thr, -1);
27254 DUK_HBUFOBJ_ASSERT_VALID(res);
27255 DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1)));
27256
27257 tv_dst = duk_get_borrowed_this_tval(thr);
27258 DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
27259 duk_pop(thr);
27260
27261 return res;
27262}
27263
27264#define DUK__BUFOBJ_FLAG_THROW (1 << 0)
27265#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1)
27266
27267/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is
27268 * always a duk_hbufobj *. Without the flag the return value can also be a
27269 * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
27270 */
27271DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) {
27272 duk_tval *tv;
27273 duk_hbufobj *h_this;
27274
27275 DUK_ASSERT(thr != NULL);
27276
27277 tv = duk_get_borrowed_this_tval(thr);
27278 DUK_ASSERT(tv != NULL);
27279
27280 if (DUK_TVAL_IS_OBJECT(tv)) {
27281 h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
27282 DUK_ASSERT(h_this != NULL);
27283 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) {
27284 DUK_HBUFOBJ_ASSERT_VALID(h_this);
27285 return (duk_heaphdr *) h_this;
27286 }
27287 } else if (DUK_TVAL_IS_BUFFER(tv)) {
27288 if (flags & DUK__BUFOBJ_FLAG_PROMOTE) {
27289 /* Promote a plain buffer to a Uint8Array. This is very
27290 * inefficient but allows plain buffer to be used wherever an
27291 * Uint8Array is used with very small cost; hot path functions
27292 * like index read/write calls should provide direct buffer
27293 * support to avoid promotion.
27294 */
27295 /* XXX: make this conditional to a flag if call sites need it? */
27296 h_this = duk__hbufobj_promote_this(thr);
27297 DUK_ASSERT(h_this != NULL);
27298 DUK_HBUFOBJ_ASSERT_VALID(h_this);
27299 return (duk_heaphdr *) h_this;
27300 } else {
27301 /* XXX: ugly, share return pointer for duk_hbuffer. */
27302 return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv);
27303 }
27304 }
27305
27306 if (flags & DUK__BUFOBJ_FLAG_THROW) {
27307 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
27308 DUK_WO_NORETURN(return NULL;);
27309 }
27310 return NULL;
27311}
27312
27313/* Check that 'this' is a duk_hbufobj and return a pointer to it. */
27314DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) {
27315 return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE);
27316}
27317
27318/* Check that 'this' is a duk_hbufobj and return a pointer to it
27319 * (NULL if not).
27320 */
27321DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) {
27322 return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
27323}
27324
27325/* Check that value is a duk_hbufobj and return a pointer to it. */
27326DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) {
27327 duk_tval *tv;
27328 duk_hbufobj *h_obj;
27329
27330 /* Don't accept relative indices now. */
27331 DUK_ASSERT(idx >= 0);
27332
27333 tv = duk_require_tval(thr, idx);
27334 DUK_ASSERT(tv != NULL);
27335 if (DUK_TVAL_IS_OBJECT(tv)) {
27336 h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
27337 DUK_ASSERT(h_obj != NULL);
27338 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) {
27339 DUK_HBUFOBJ_ASSERT_VALID(h_obj);
27340 return h_obj;
27341 }
27342 } else if (DUK_TVAL_IS_BUFFER(tv)) {
27343 h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx);
27344 DUK_ASSERT(h_obj != NULL);
27345 DUK_HBUFOBJ_ASSERT_VALID(h_obj);
27346 return h_obj;
27347 }
27348
27349 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
27350 DUK_WO_NORETURN(return NULL;);
27351}
27352
27353DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
27354 DUK_ASSERT(thr != NULL);
27355 DUK_ASSERT(h_bufobj != NULL);
27356 DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
27357 DUK_ASSERT(h_val != NULL);
27358 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
27359 DUK_UNREF(thr);
27360
27361 h_bufobj->buf = h_val;
27362 DUK_HBUFFER_INCREF(thr, h_val);
27363 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
27364 DUK_ASSERT(h_bufobj->shift == 0);
27365 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
27366 DUK_ASSERT(h_bufobj->is_typedarray == 0);
27367
27368 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
27369}
27370
27371/* Shared offset/length coercion helper. */
27372DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
27373 duk_hbufobj *h_bufarg,
27374 duk_idx_t idx_offset,
27375 duk_idx_t idx_length,
27376 duk_uint_t *out_offset,
27377 duk_uint_t *out_length,
27378 duk_bool_t throw_flag) {
27379 duk_int_t offset_signed;
27380 duk_int_t length_signed;
27381 duk_uint_t offset;
27382 duk_uint_t length;
27383
27384 offset_signed = duk_to_int(thr, idx_offset);
27385 if (offset_signed < 0) {
27386 goto fail_range;
27387 }
27388 offset = (duk_uint_t) offset_signed;
27389 if (offset > h_bufarg->length) {
27390 goto fail_range;
27391 }
27392 DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
27393 DUK_ASSERT(offset <= h_bufarg->length);
27394
27395 if (duk_is_undefined(thr, idx_length)) {
27396 DUK_ASSERT(h_bufarg->length >= offset);
27397 length = h_bufarg->length - offset; /* >= 0 */
27398 } else {
27399 length_signed = duk_to_int(thr, idx_length);
27400 if (length_signed < 0) {
27401 goto fail_range;
27402 }
27403 length = (duk_uint_t) length_signed;
27404 DUK_ASSERT(h_bufarg->length >= offset);
27405 if (length > h_bufarg->length - offset) {
27406 /* Unlike for negative arguments, some call sites
27407 * want length to be clamped if it's positive.
27408 */
27409 if (throw_flag) {
27410 goto fail_range;
27411 } else {
27412 length = h_bufarg->length - offset;
27413 }
27414 }
27415 }
27416 DUK_ASSERT_DISABLE(length >= 0); /* unsigned */
27417 DUK_ASSERT(offset + length <= h_bufarg->length);
27418
27419 *out_offset = offset;
27420 *out_length = length;
27421 return;
27422
27423 fail_range:
27424 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
27425 DUK_WO_NORETURN(return;);
27426}
27427
27428/* Shared lenient buffer length clamping helper. No negative indices, no
27429 * element/byte shifting.
27430 */
27431DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr,
27432 duk_int_t buffer_length,
27433 duk_idx_t idx_start,
27434 duk_idx_t idx_end,
27435 duk_int_t *out_start_offset,
27436 duk_int_t *out_end_offset) {
27437 duk_int_t start_offset;
27438 duk_int_t end_offset;
27439
27440 DUK_ASSERT(out_start_offset != NULL);
27441 DUK_ASSERT(out_end_offset != NULL);
27442
27443 /* undefined coerces to zero which is correct */
27444 start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length);
27445 if (duk_is_undefined(thr, idx_end)) {
27446 end_offset = buffer_length;
27447 } else {
27448 end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length);
27449 }
27450
27451 DUK_ASSERT(start_offset >= 0);
27452 DUK_ASSERT(start_offset <= buffer_length);
27453 DUK_ASSERT(end_offset >= 0);
27454 DUK_ASSERT(end_offset <= buffer_length);
27455 DUK_ASSERT(start_offset <= end_offset);
27456
27457 *out_start_offset = start_offset;
27458 *out_end_offset = end_offset;
27459}
27460
27461/* Shared lenient buffer length clamping helper. Indices are treated as
27462 * element indices (though output values are byte offsets) which only
27463 * really matters for TypedArray views as other buffer object have a zero
27464 * shift. Negative indices are counted from end of input slice; crossed
27465 * indices are clamped to zero length; and final indices are clamped
27466 * against input slice. Used for e.g. ArrayBuffer slice().
27467 */
27468DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr,
27469 duk_int_t buffer_length,
27470 duk_uint8_t buffer_shift,
27471 duk_idx_t idx_start,
27472 duk_idx_t idx_end,
27473 duk_int_t *out_start_offset,
27474 duk_int_t *out_end_offset) {
27475 duk_int_t start_offset;
27476 duk_int_t end_offset;
27477
27478 DUK_ASSERT(out_start_offset != NULL);
27479 DUK_ASSERT(out_end_offset != NULL);
27480
27481 buffer_length >>= buffer_shift; /* as (full) elements */
27482
27483 /* Resolve start/end offset as element indices first; arguments
27484 * at idx_start/idx_end are element offsets. Working with element
27485 * indices first also avoids potential for wrapping.
27486 */
27487
27488 start_offset = duk_to_int(thr, idx_start);
27489 if (start_offset < 0) {
27490 start_offset = buffer_length + start_offset;
27491 }
27492 if (duk_is_undefined(thr, idx_end)) {
27493 end_offset = buffer_length;
27494 } else {
27495 end_offset = duk_to_int(thr, idx_end);
27496 if (end_offset < 0) {
27497 end_offset = buffer_length + end_offset;
27498 }
27499 }
27500 /* Note: start_offset/end_offset can still be < 0 here. */
27501
27502 if (start_offset < 0) {
27503 start_offset = 0;
27504 } else if (start_offset > buffer_length) {
27505 start_offset = buffer_length;
27506 }
27507 if (end_offset < start_offset) {
27508 end_offset = start_offset;
27509 } else if (end_offset > buffer_length) {
27510 end_offset = buffer_length;
27511 }
27512 DUK_ASSERT(start_offset >= 0);
27513 DUK_ASSERT(start_offset <= buffer_length);
27514 DUK_ASSERT(end_offset >= 0);
27515 DUK_ASSERT(end_offset <= buffer_length);
27516 DUK_ASSERT(start_offset <= end_offset);
27517
27518 /* Convert indices to byte offsets. */
27519 start_offset <<= buffer_shift;
27520 end_offset <<= buffer_shift;
27521
27522 *out_start_offset = start_offset;
27523 *out_end_offset = end_offset;
27524}
27525
27526DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) {
27527 if (duk_is_buffer(thr, idx)) {
27528 duk_to_object(thr, idx);
27529 }
27530}
27531
27532DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
27533 /* Push Uint8Array which will share the same underlying buffer as
27534 * the plain buffer argument. Also create an ArrayBuffer with the
27535 * same backing for the result .buffer property.
27536 */
27537
27538 duk_push_hbuffer(thr, h_buf);
27539 duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
27540 duk_remove_m2(thr);
27541
27542#if 0
27543 /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
27544 h_bufobj = duk_push_bufobj_raw(thr,
27545 DUK_HOBJECT_FLAG_EXTENSIBLE |
27546 DUK_HOBJECT_FLAG_BUFOBJ |
27547 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
27548 DUK_BIDX_UINT8ARRAY_PROTOTYPE);
27549 DUK_ASSERT(h_bufobj != NULL);
27550 duk__set_bufobj_buffer(thr, h_bufobj, h_buf);
27551 h_bufobj->is_typedarray = 1;
27552 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
27553
27554 h_arrbuf = duk_push_bufobj_raw(thr,
27555 DUK_HOBJECT_FLAG_EXTENSIBLE |
27556 DUK_HOBJECT_FLAG_BUFOBJ |
27557 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
27558 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
27559 DUK_ASSERT(h_arrbuf != NULL);
27560 duk__set_bufobj_buffer(thr, h_arrbuf, h_buf);
27561 DUK_ASSERT(h_arrbuf->is_typedarray == 0);
27562 DUK_HBUFOBJ_ASSERT_VALID(h_arrbuf);
27563
27564 DUK_ASSERT(h_bufobj->buf_prop == NULL);
27565 h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
27566 DUK_ASSERT(h_arrbuf != NULL);
27567 DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
27568 duk_pop(thr);
27569#endif
27570}
27571
27572/* Indexed read helper for buffer objects, also called from outside this file. */
27573DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
27574 duk_double_union du;
27575
27576 DUK_ASSERT(elem_size > 0);
27577 duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size);
27578
27579 switch (h_bufobj->elem_type) {
27580 case DUK_HBUFOBJ_ELEM_UINT8:
27581 case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
27582 duk_push_uint(thr, (duk_uint_t) du.uc[0]);
27583 break;
27584 case DUK_HBUFOBJ_ELEM_INT8:
27585 duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]);
27586 break;
27587 case DUK_HBUFOBJ_ELEM_UINT16:
27588 duk_push_uint(thr, (duk_uint_t) du.us[0]);
27589 break;
27590 case DUK_HBUFOBJ_ELEM_INT16:
27591 duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]);
27592 break;
27593 case DUK_HBUFOBJ_ELEM_UINT32:
27594 duk_push_uint(thr, (duk_uint_t) du.ui[0]);
27595 break;
27596 case DUK_HBUFOBJ_ELEM_INT32:
27597 duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]);
27598 break;
27599 case DUK_HBUFOBJ_ELEM_FLOAT32:
27600 duk_push_number(thr, (duk_double_t) du.f[0]);
27601 break;
27602 case DUK_HBUFOBJ_ELEM_FLOAT64:
27603 duk_push_number(thr, (duk_double_t) du.d);
27604 break;
27605 default:
27606 DUK_UNREACHABLE();
27607 }
27608}
27609
27610/* Indexed write helper for buffer objects, also called from outside this file. */
27611DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
27612 duk_double_union du;
27613
27614 /* NOTE! Caller must ensure that any side effects from the
27615 * coercions below are safe. If that cannot be guaranteed
27616 * (which is normally the case), caller must coerce the
27617 * argument using duk_to_number() before any pointer
27618 * validations; the result of duk_to_number() always coerces
27619 * without side effects here.
27620 */
27621
27622 switch (h_bufobj->elem_type) {
27623 case DUK_HBUFOBJ_ELEM_UINT8:
27624 du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1);
27625 break;
27626 case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
27627 du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1);
27628 break;
27629 case DUK_HBUFOBJ_ELEM_INT8:
27630 du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1);
27631 break;
27632 case DUK_HBUFOBJ_ELEM_UINT16:
27633 du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1);
27634 break;
27635 case DUK_HBUFOBJ_ELEM_INT16:
27636 du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1);
27637 break;
27638 case DUK_HBUFOBJ_ELEM_UINT32:
27639 du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1);
27640 break;
27641 case DUK_HBUFOBJ_ELEM_INT32:
27642 du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
27643 break;
27644 case DUK_HBUFOBJ_ELEM_FLOAT32:
27645 /* A double-to-float cast is undefined behavior in C99 if
27646 * the cast is out-of-range, so use a helper. Example:
27647 * runtime error: value -1e+100 is outside the range of representable values of type 'float'
27648 */
27649 du.f[0] = duk_double_to_float_t(duk_to_number_m1(thr));
27650 break;
27651 case DUK_HBUFOBJ_ELEM_FLOAT64:
27652 du.d = (duk_double_t) duk_to_number_m1(thr);
27653 break;
27654 default:
27655 DUK_UNREACHABLE();
27656 }
27657
27658 DUK_ASSERT(elem_size > 0);
27659 duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size);
27660}
27661
27662/* Helper to create a fixed buffer from argument value at index 0.
27663 * Node.js and allocPlain() compatible.
27664 */
27665DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
27666 duk_int_t len;
27667 duk_int_t i;
27668 duk_size_t buf_size;
27669 duk_uint8_t *buf;
27670
27671 switch (duk_get_type(thr, 0)) {
27672 case DUK_TYPE_NUMBER: {
27673 len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX);
27674 (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
27675 break;
27676 }
27677 case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
27678 goto slow_copy;
27679 }
27680 case DUK_TYPE_OBJECT: {
27681 duk_hobject *h;
27682 duk_hbufobj *h_bufobj;
27683
27684 /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer
27685 * that shares allocated memory with the given ArrayBuffer."
27686 * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
27687 */
27688
27689 h = duk_known_hobject(thr, 0);
27690 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
27691 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
27692 h_bufobj = (duk_hbufobj *) h;
27693 if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
27694 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27695 DUK_WO_NORETURN(return NULL;);
27696 }
27697 if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
27698 /* No support for ArrayBuffers with slice
27699 * offset/length.
27700 */
27701 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27702 DUK_WO_NORETURN(return NULL;);
27703 }
27704 duk_push_hbuffer(thr, h_bufobj->buf);
27705 return h_bufobj->buf;
27706 }
27707 goto slow_copy;
27708 }
27709 case DUK_TYPE_STRING: {
27710 /* ignore encoding for now */
27711 duk_require_hstring_notsymbol(thr, 0);
27712 duk_dup_0(thr);
27713 (void) duk_to_buffer(thr, -1, &buf_size);
27714 break;
27715 }
27716 default:
27717 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27718 DUK_WO_NORETURN(return NULL;);
27719 }
27720
27721 done:
27722 DUK_ASSERT(duk_is_buffer(thr, -1));
27723 return duk_known_hbuffer(thr, -1);
27724
27725 slow_copy:
27726 /* XXX: fast path for typed arrays and other buffer objects? */
27727
27728 (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
27729 len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX);
27730 duk_pop(thr);
27731 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */
27732 for (i = 0; i < len; i++) {
27733 /* XXX: fast path for array or buffer arguments? */
27734 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
27735 buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU);
27736 duk_pop(thr);
27737 }
27738 goto done;
27739}
27740#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
27741
27742/*
27743 * Node.js Buffer constructor
27744 *
27745 * Node.js Buffers are just Uint8Arrays with internal prototype set to
27746 * Buffer.prototype so they're handled otherwise the same as Uint8Array.
27747 * However, the constructor arguments are very different so a separate
27748 * constructor entry point is used.
27749 */
27750#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27751DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
27752 duk_hbuffer *h_buf;
27753
27754 h_buf = duk__hbufobj_fixed_from_argvalue(thr);
27755 DUK_ASSERT(h_buf != NULL);
27756
27757 duk_push_buffer_object(thr,
27758 -1,
27759 0,
27760 DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) (void *) h_buf),
27761 DUK_BUFOBJ_UINT8ARRAY);
27762 duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
27763 duk_set_prototype(thr, -2);
27764
27765 /* XXX: a more direct implementation */
27766
27767 return 1;
27768}
27769#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
27770
27771/*
27772 * ArrayBuffer, DataView, and TypedArray constructors
27773 */
27774
27775#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27776DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) {
27777 duk_hbufobj *h_bufobj;
27778 duk_hbuffer *h_val;
27779 duk_int_t len;
27780
27781 DUK_CTX_ASSERT_VALID(thr);
27782
27783 duk_require_constructor_call(thr);
27784
27785 len = duk_to_int(thr, 0);
27786 if (len < 0) {
27787 goto fail_length;
27788 }
27789 (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
27790 h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1);
27791
27792 h_bufobj = duk_push_bufobj_raw(thr,
27793 DUK_HOBJECT_FLAG_EXTENSIBLE |
27794 DUK_HOBJECT_FLAG_BUFOBJ |
27795 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
27796 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
27797 DUK_ASSERT(h_bufobj != NULL);
27798
27799 duk__set_bufobj_buffer(thr, h_bufobj, h_val);
27800 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
27801
27802 return 1;
27803
27804 fail_length:
27805 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
27806}
27807#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
27808
27809
27810/* Format of magic, bits:
27811 * 0...1: elem size shift (0-3)
27812 * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx)
27813 *
27814 * XXX: add prototype bidx explicitly to magic instead of using a mapping?
27815 */
27816
27817#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27818DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
27819 duk_tval *tv;
27820 duk_hobject *h_obj;
27821 duk_hbufobj *h_bufobj = NULL;
27822 duk_hbufobj *h_bufarg = NULL;
27823 duk_hbuffer *h_val;
27824 duk_small_uint_t magic;
27825 duk_small_uint_t shift;
27826 duk_small_uint_t elem_type;
27827 duk_small_uint_t elem_size;
27828 duk_small_uint_t class_num;
27829 duk_small_uint_t proto_bidx;
27830 duk_uint_t align_mask;
27831 duk_uint_t elem_length;
27832 duk_int_t elem_length_signed;
27833 duk_uint_t byte_length;
27834 duk_small_uint_t copy_mode;
27835
27836 /* XXX: The same copy helpers could be shared with at least some
27837 * buffer functions.
27838 */
27839
27840 duk_require_constructor_call(thr);
27841
27842 /* We could fit built-in index into magic but that'd make the magic
27843 * number dependent on built-in numbering (genbuiltins.py doesn't
27844 * handle that yet). So map both class and prototype from the
27845 * element type.
27846 */
27847 magic = (duk_small_uint_t) duk_get_current_magic(thr);
27848 shift = magic & 0x03U; /* bits 0...1: shift */
27849 elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */
27850 elem_size = 1U << shift;
27851 align_mask = elem_size - 1;
27852 DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
27853 proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
27854 DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
27855 DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
27856 class_num = duk__buffer_class_from_elemtype[elem_type];
27857
27858 DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
27859 "elem_size=%d, proto_bidx=%d, class_num=%d",
27860 (int) magic, (int) shift, (int) elem_type, (int) elem_size,
27861 (int) proto_bidx, (int) class_num));
27862
27863 /* Argument variants. When the argument is an ArrayBuffer a view to
27864 * the same buffer is created; otherwise a new ArrayBuffer is always
27865 * created.
27866 */
27867
27868 /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer:
27869 * coerce to an ArrayBuffer object and use that as .buffer. The underlying
27870 * buffer will be the same but result .buffer !== inputPlainBuffer.
27871 */
27872 duk_hbufobj_promote_plain(thr, 0);
27873
27874 tv = duk_get_tval(thr, 0);
27875 DUK_ASSERT(tv != NULL); /* arg count */
27876 if (DUK_TVAL_IS_OBJECT(tv)) {
27877 h_obj = DUK_TVAL_GET_OBJECT(tv);
27878 DUK_ASSERT(h_obj != NULL);
27879
27880 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
27881 /* ArrayBuffer: unlike any other argument variant, create
27882 * a view into the existing buffer.
27883 */
27884
27885 duk_int_t byte_offset_signed;
27886 duk_uint_t byte_offset;
27887
27888 h_bufarg = (duk_hbufobj *) h_obj;
27889
27890 byte_offset_signed = duk_to_int(thr, 1);
27891 if (byte_offset_signed < 0) {
27892 goto fail_arguments;
27893 }
27894 byte_offset = (duk_uint_t) byte_offset_signed;
27895 if (byte_offset > h_bufarg->length ||
27896 (byte_offset & align_mask) != 0) {
27897 /* Must be >= 0 and multiple of element size. */
27898 goto fail_arguments;
27899 }
27900 if (duk_is_undefined(thr, 2)) {
27901 DUK_ASSERT(h_bufarg->length >= byte_offset);
27902 byte_length = h_bufarg->length - byte_offset;
27903 if ((byte_length & align_mask) != 0) {
27904 /* Must be element size multiple from
27905 * start offset to end of buffer.
27906 */
27907 goto fail_arguments;
27908 }
27909 elem_length = (byte_length >> shift);
27910 } else {
27911 elem_length_signed = duk_to_int(thr, 2);
27912 if (elem_length_signed < 0) {
27913 goto fail_arguments;
27914 }
27915 elem_length = (duk_uint_t) elem_length_signed;
27916 byte_length = elem_length << shift;
27917 if ((byte_length >> shift) != elem_length) {
27918 /* Byte length would overflow. */
27919 /* XXX: easier check with less code? */
27920 goto fail_arguments;
27921 }
27922 DUK_ASSERT(h_bufarg->length >= byte_offset);
27923 if (byte_length > h_bufarg->length - byte_offset) {
27924 /* Not enough data. */
27925 goto fail_arguments;
27926 }
27927 }
27928 DUK_UNREF(elem_length);
27929 DUK_ASSERT_DISABLE(byte_offset >= 0);
27930 DUK_ASSERT(byte_offset <= h_bufarg->length);
27931 DUK_ASSERT_DISABLE(byte_length >= 0);
27932 DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
27933 DUK_ASSERT((elem_length << shift) == byte_length);
27934
27935 h_bufobj = duk_push_bufobj_raw(thr,
27936 DUK_HOBJECT_FLAG_EXTENSIBLE |
27937 DUK_HOBJECT_FLAG_BUFOBJ |
27938 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
27939 (duk_small_int_t) proto_bidx);
27940 h_val = h_bufarg->buf;
27941 if (h_val == NULL) {
27942 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27943 }
27944 h_bufobj->buf = h_val;
27945 DUK_HBUFFER_INCREF(thr, h_val);
27946 h_bufobj->offset = h_bufarg->offset + byte_offset;
27947 h_bufobj->length = byte_length;
27948 h_bufobj->shift = (duk_uint8_t) shift;
27949 h_bufobj->elem_type = (duk_uint8_t) elem_type;
27950 h_bufobj->is_typedarray = 1;
27951 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
27952
27953 /* Set .buffer to the argument ArrayBuffer. */
27954 DUK_ASSERT(h_bufobj->buf_prop == NULL);
27955 h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
27956 DUK_ASSERT(h_bufarg != NULL);
27957 DUK_HBUFOBJ_INCREF(thr, h_bufarg);
27958 return 1;
27959 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
27960 /* TypedArray (or other non-ArrayBuffer duk_hbufobj).
27961 * Conceptually same behavior as for an Array-like argument,
27962 * with a few fast paths.
27963 */
27964
27965 h_bufarg = (duk_hbufobj *) h_obj;
27966 DUK_HBUFOBJ_ASSERT_VALID(h_bufarg);
27967 elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
27968 if (h_bufarg->buf == NULL) {
27969 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27970 }
27971
27972 /* Select copy mode. Must take into account element
27973 * compatibility and validity of the underlying source
27974 * buffer.
27975 */
27976
27977 DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
27978 "src byte_length=%ld, src shift=%d, "
27979 "src/dst elem_length=%ld; "
27980 "dst shift=%d -> dst byte_length=%ld",
27981 (long) h_bufarg->length, (int) h_bufarg->shift,
27982 (long) elem_length_signed, (int) shift,
27983 (long) (elem_length_signed << shift)));
27984
27985 copy_mode = 2; /* default is explicit index read/write copy */
27986#if !defined(DUK_USE_PREFER_SIZE)
27987 /* With a size optimized build copy_mode 2 is enough.
27988 * Modes 0 and 1 are faster but conceptually the same.
27989 */
27990 DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
27991 if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
27992 if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
27993 DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
27994 DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
27995 copy_mode = 0;
27996 } else {
27997 DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
27998 copy_mode = 1;
27999 }
28000 }
28001#endif /* !DUK_USE_PREFER_SIZE */
28002 } else {
28003 /* Array or Array-like */
28004 elem_length_signed = (duk_int_t) duk_get_length(thr, 0);
28005 copy_mode = 2;
28006 }
28007 } else {
28008 /* Non-object argument is simply int coerced, matches
28009 * V8 behavior (except for "null", which we coerce to
28010 * 0 but V8 TypeErrors).
28011 */
28012 elem_length_signed = duk_to_int(thr, 0);
28013 copy_mode = 3;
28014 }
28015 if (elem_length_signed < 0) {
28016 goto fail_arguments;
28017 }
28018 elem_length = (duk_uint_t) elem_length_signed;
28019 byte_length = (duk_uint_t) (elem_length << shift);
28020 if ((byte_length >> shift) != elem_length) {
28021 /* Byte length would overflow. */
28022 /* XXX: easier check with less code? */
28023 goto fail_arguments;
28024 }
28025
28026 DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
28027 (long) elem_length, (long) byte_length));
28028
28029 /* ArrayBuffer argument is handled specially above; the rest of the
28030 * argument variants are handled by shared code below.
28031 *
28032 * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset.
28033 * It will be automatically created by the .buffer accessor on
28034 * first access.
28035 */
28036
28037 /* Push the resulting view object on top of a plain fixed buffer. */
28038 (void) duk_push_fixed_buffer(thr, byte_length);
28039 h_val = duk_known_hbuffer(thr, -1);
28040 DUK_ASSERT(h_val != NULL);
28041
28042 h_bufobj = duk_push_bufobj_raw(thr,
28043 DUK_HOBJECT_FLAG_EXTENSIBLE |
28044 DUK_HOBJECT_FLAG_BUFOBJ |
28045 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
28046 (duk_small_int_t) proto_bidx);
28047
28048 h_bufobj->buf = h_val;
28049 DUK_HBUFFER_INCREF(thr, h_val);
28050 DUK_ASSERT(h_bufobj->offset == 0);
28051 h_bufobj->length = byte_length;
28052 h_bufobj->shift = (duk_uint8_t) shift;
28053 h_bufobj->elem_type = (duk_uint8_t) elem_type;
28054 h_bufobj->is_typedarray = 1;
28055 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
28056
28057 /* Copy values, the copy method depends on the arguments.
28058 *
28059 * Copy mode decision may depend on the validity of the underlying
28060 * buffer of the source argument; there must be no harmful side effects
28061 * from there to here for copy_mode to still be valid.
28062 */
28063 DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
28064 switch (copy_mode) {
28065 /* Copy modes 0 and 1 can be omitted in size optimized build,
28066 * copy mode 2 handles them (but more slowly).
28067 */
28068#if !defined(DUK_USE_PREFER_SIZE)
28069 case 0: {
28070 /* Use byte copy. */
28071
28072 duk_uint8_t *p_src;
28073 duk_uint8_t *p_dst;
28074
28075 DUK_ASSERT(h_bufobj != NULL);
28076 DUK_ASSERT(h_bufobj->buf != NULL);
28077 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
28078 DUK_ASSERT(h_bufarg != NULL);
28079 DUK_ASSERT(h_bufarg->buf != NULL);
28080 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
28081
28082 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
28083 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
28084
28085 DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
28086 (void *) p_src, (void *) p_dst, (long) byte_length));
28087
28088 duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length);
28089 break;
28090 }
28091 case 1: {
28092 /* Copy values through direct validated reads and writes. */
28093
28094 duk_small_uint_t src_elem_size;
28095 duk_small_uint_t dst_elem_size;
28096 duk_uint8_t *p_src;
28097 duk_uint8_t *p_src_end;
28098 duk_uint8_t *p_dst;
28099
28100 DUK_ASSERT(h_bufobj != NULL);
28101 DUK_ASSERT(h_bufobj->buf != NULL);
28102 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
28103 DUK_ASSERT(h_bufarg != NULL);
28104 DUK_ASSERT(h_bufarg->buf != NULL);
28105 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
28106
28107 src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
28108 dst_elem_size = elem_size;
28109
28110 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
28111 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
28112 p_src_end = p_src + h_bufarg->length;
28113
28114 DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
28115 "src_elem_size=%d, dst_elem_size=%d",
28116 (void *) p_src, (void *) p_src_end, (void *) p_dst,
28117 (int) src_elem_size, (int) dst_elem_size));
28118
28119 while (p_src != p_src_end) {
28120 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
28121 "p_src=%p, p_src_end=%p, p_dst=%p",
28122 (void *) p_src, (void *) p_src_end, (void *) p_dst));
28123 /* A validated read() is always a number, so it's write coercion
28124 * is always side effect free an won't invalidate pointers etc.
28125 */
28126 duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
28127 duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size);
28128 duk_pop(thr);
28129 p_src += src_elem_size;
28130 p_dst += dst_elem_size;
28131 }
28132 break;
28133 }
28134#endif /* !DUK_USE_PREFER_SIZE */
28135 case 2: {
28136 /* Copy values by index reads and writes. Let virtual
28137 * property handling take care of coercion.
28138 */
28139 duk_uint_t i;
28140
28141 DUK_DDD(DUK_DDDPRINT("using slow copy"));
28142
28143 for (i = 0; i < elem_length; i++) {
28144 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
28145 duk_put_prop_index(thr, -2, (duk_uarridx_t) i);
28146 }
28147 break;
28148 }
28149 default:
28150 case 3: {
28151 /* No copy, leave zero bytes in the buffer. There's no
28152 * ambiguity with Float32/Float64 because zero bytes also
28153 * represent 0.0.
28154 */
28155
28156 DUK_DDD(DUK_DDDPRINT("using no copy"));
28157 break;
28158 }
28159 }
28160
28161 return 1;
28162
28163 fail_arguments:
28164 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28165}
28166#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
28167/* When bufferobject support is disabled, new Uint8Array() could still be
28168 * supported to create a plain fixed buffer. Disabled for now.
28169 */
28170#if 0
28171DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
28172 duk_int_t elem_length_signed;
28173 duk_uint_t byte_length;
28174
28175 /* XXX: The same copy helpers could be shared with at least some
28176 * buffer functions.
28177 */
28178
28179 duk_require_constructor_call(thr);
28180
28181 elem_length_signed = duk_require_int(thr, 0);
28182 if (elem_length_signed < 0) {
28183 goto fail_arguments;
28184 }
28185 byte_length = (duk_uint_t) elem_length_signed;
28186
28187 (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length);
28188 return 1;
28189
28190 fail_arguments:
28191 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28192}
28193#endif /* 0 */
28194#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28195
28196#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28197DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) {
28198 duk_hbufobj *h_bufarg;
28199 duk_hbufobj *h_bufobj;
28200 duk_hbuffer *h_val;
28201 duk_uint_t offset;
28202 duk_uint_t length;
28203
28204 duk_require_constructor_call(thr);
28205
28206 h_bufarg = duk__require_bufobj_value(thr, 0);
28207 DUK_ASSERT(h_bufarg != NULL);
28208 if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
28209 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28210 }
28211
28212 duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
28213 DUK_ASSERT(offset <= h_bufarg->length);
28214 DUK_ASSERT(offset + length <= h_bufarg->length);
28215
28216 h_bufobj = duk_push_bufobj_raw(thr,
28217 DUK_HOBJECT_FLAG_EXTENSIBLE |
28218 DUK_HOBJECT_FLAG_BUFOBJ |
28219 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
28220 DUK_BIDX_DATAVIEW_PROTOTYPE);
28221
28222 h_val = h_bufarg->buf;
28223 if (h_val == NULL) {
28224 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28225 }
28226 h_bufobj->buf = h_val;
28227 DUK_HBUFFER_INCREF(thr, h_val);
28228 h_bufobj->offset = h_bufarg->offset + offset;
28229 h_bufobj->length = length;
28230 DUK_ASSERT(h_bufobj->shift == 0);
28231 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
28232 DUK_ASSERT(h_bufobj->is_typedarray == 0);
28233
28234 DUK_ASSERT(h_bufobj->buf_prop == NULL);
28235 h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
28236 DUK_ASSERT(h_bufarg != NULL);
28237 DUK_HBUFOBJ_INCREF(thr, h_bufarg);
28238
28239 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
28240 return 1;
28241}
28242#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28243
28244/*
28245 * ArrayBuffer.isView()
28246 */
28247
28248#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28249DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) {
28250 duk_hobject *h_obj;
28251 duk_bool_t ret = 0;
28252
28253 if (duk_is_buffer(thr, 0)) {
28254 ret = 1;
28255 } else {
28256 h_obj = duk_get_hobject(thr, 0);
28257 if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
28258 /* DataView needs special casing: ArrayBuffer.isView() is
28259 * true, but ->is_typedarray is 0.
28260 */
28261 ret = ((duk_hbufobj *) h_obj)->is_typedarray ||
28262 (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
28263 }
28264 }
28265 duk_push_boolean(thr, ret);
28266 return 1;
28267}
28268#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28269
28270/*
28271 * Uint8Array.allocPlain()
28272 */
28273
28274#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28275DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) {
28276 duk__hbufobj_fixed_from_argvalue(thr);
28277 return 1;
28278}
28279#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28280
28281/*
28282 * Uint8Array.plainOf()
28283 */
28284
28285#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28286DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) {
28287 duk_hbufobj *h_bufobj;
28288
28289#if !defined(DUK_USE_PREFER_SIZE)
28290 /* Avoid churn if argument is already a plain buffer. */
28291 if (duk_is_buffer(thr, 0)) {
28292 return 1;
28293 }
28294#endif
28295
28296 /* Promotes plain buffers to ArrayBuffers, so for a plain buffer
28297 * argument we'll create a pointless temporary (but still work
28298 * correctly).
28299 */
28300 h_bufobj = duk__require_bufobj_value(thr, 0);
28301 if (h_bufobj->buf == NULL) {
28302 duk_push_undefined(thr);
28303 } else {
28304 duk_push_hbuffer(thr, h_bufobj->buf);
28305 }
28306 return 1;
28307}
28308#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28309
28310/*
28311 * Node.js Buffer: toString([encoding], [start], [end])
28312 */
28313
28314#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28315DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
28316 duk_hbufobj *h_this;
28317 duk_int_t start_offset, end_offset;
28318 duk_uint8_t *buf_slice;
28319 duk_size_t slice_length;
28320
28321 h_this = duk__get_bufobj_this(thr);
28322 if (h_this == NULL) {
28323 /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
28324 duk_push_literal(thr, "[object Object]");
28325 return 1;
28326 }
28327 DUK_HBUFOBJ_ASSERT_VALID(h_this);
28328
28329 /* Ignore encoding for now. */
28330
28331 duk__clamp_startend_nonegidx_noshift(thr,
28332 (duk_int_t) h_this->length,
28333 1 /*idx_start*/,
28334 2 /*idx_end*/,
28335 &start_offset,
28336 &end_offset);
28337
28338 slice_length = (duk_size_t) (end_offset - start_offset);
28339 buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */
28340 DUK_ASSERT(buf_slice != NULL);
28341
28342 /* Neutered or uncovered, TypeError. */
28343 if (h_this->buf == NULL ||
28344 !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) {
28345 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28346 }
28347
28348 /* XXX: ideally we wouldn't make a copy but a view into the buffer for the
28349 * decoding process. Or the decoding helper could be changed to accept
28350 * the slice info (a buffer pointer is NOT a good approach because guaranteeing
28351 * its stability is difficult).
28352 */
28353
28354 DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
28355 duk_memcpy_unsafe((void *) buf_slice,
28356 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
28357 (size_t) slice_length);
28358
28359 /* Use the equivalent of: new TextEncoder().encode(this) to convert the
28360 * string. Result will be valid UTF-8; non-CESU-8 inputs are currently
28361 * interpreted loosely. Value stack convention is a bit odd for now.
28362 */
28363 duk_replace(thr, 0);
28364 duk_set_top(thr, 1);
28365 return duk_textdecoder_decode_utf8_nodejs(thr);
28366}
28367#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28368
28369/*
28370 * Node.js Buffer.prototype: toJSON()
28371 */
28372
28373#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28374DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) {
28375 duk_hbufobj *h_this;
28376 duk_uint8_t *buf;
28377 duk_uint_t i, n;
28378 duk_tval *tv;
28379
28380 h_this = duk__require_bufobj_this(thr);
28381 DUK_ASSERT(h_this != NULL);
28382
28383 if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
28384 /* Serialize uncovered backing buffer as a null; doesn't
28385 * really matter as long we're memory safe.
28386 */
28387 duk_push_null(thr);
28388 return 1;
28389 }
28390
28391 duk_push_object(thr);
28392 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER);
28393 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE);
28394
28395 /* XXX: uninitialized would be OK */
28396 DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
28397 tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
28398 DUK_ASSERT(!duk_is_bare_object(thr, -1));
28399
28400 DUK_ASSERT(h_this->buf != NULL);
28401 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
28402 for (i = 0, n = h_this->length; i < n; i++) {
28403 DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */
28404 }
28405 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA);
28406
28407 return 1;
28408}
28409#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28410
28411/*
28412 * Node.js Buffer.prototype.equals()
28413 * Node.js Buffer.prototype.compare()
28414 * Node.js Buffer.compare()
28415 */
28416
28417#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28418DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) {
28419 duk_small_uint_t magic;
28420 duk_hbufobj *h_bufarg1;
28421 duk_hbufobj *h_bufarg2;
28422 duk_small_int_t comp_res;
28423
28424 /* XXX: keep support for plain buffers and non-Node.js buffers? */
28425
28426 magic = (duk_small_uint_t) duk_get_current_magic(thr);
28427 if (magic & 0x02U) {
28428 /* Static call style. */
28429 h_bufarg1 = duk__require_bufobj_value(thr, 0);
28430 h_bufarg2 = duk__require_bufobj_value(thr, 1);
28431 } else {
28432 h_bufarg1 = duk__require_bufobj_this(thr);
28433 h_bufarg2 = duk__require_bufobj_value(thr, 0);
28434 }
28435 DUK_ASSERT(h_bufarg1 != NULL);
28436 DUK_ASSERT(h_bufarg2 != NULL);
28437
28438 /* We want to compare the slice/view areas of the arguments.
28439 * If either slice/view is invalid (underlying buffer is shorter)
28440 * ensure equals() is false, but otherwise the only thing that
28441 * matters is to be memory safe.
28442 */
28443
28444 if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) &&
28445 DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) {
28446 comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
28447 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
28448 (duk_size_t) h_bufarg1->length,
28449 (duk_size_t) h_bufarg2->length);
28450 } else {
28451 comp_res = -1; /* either nonzero value is ok */
28452 }
28453
28454 if (magic & 0x01U) {
28455 /* compare: similar to string comparison but for buffer data. */
28456 duk_push_int(thr, comp_res);
28457 } else {
28458 /* equals */
28459 duk_push_boolean(thr, (comp_res == 0));
28460 }
28461
28462 return 1;
28463}
28464#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28465
28466/*
28467 * Node.js Buffer.prototype.fill()
28468 */
28469
28470#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28471DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
28472 duk_hbufobj *h_this;
28473 const duk_uint8_t *fill_str_ptr;
28474 duk_size_t fill_str_len;
28475 duk_uint8_t fill_value;
28476 duk_int_t fill_offset;
28477 duk_int_t fill_end;
28478 duk_size_t fill_length;
28479 duk_uint8_t *p;
28480
28481 h_this = duk__require_bufobj_this(thr);
28482 DUK_ASSERT(h_this != NULL);
28483 if (h_this->buf == NULL) {
28484 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28485 }
28486
28487 /* [ value offset end ] */
28488
28489 if (duk_is_string_notsymbol(thr, 0)) {
28490 fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len);
28491 DUK_ASSERT(fill_str_ptr != NULL);
28492 } else {
28493 /* Symbols get ToNumber() coerced and cause TypeError. */
28494 fill_value = (duk_uint8_t) duk_to_uint32(thr, 0);
28495 fill_str_ptr = (const duk_uint8_t *) &fill_value;
28496 fill_str_len = 1;
28497 }
28498
28499 /* Fill offset handling is more lenient than in Node.js. */
28500
28501 duk__clamp_startend_nonegidx_noshift(thr,
28502 (duk_int_t) h_this->length,
28503 1 /*idx_start*/,
28504 2 /*idx_end*/,
28505 &fill_offset,
28506 &fill_end);
28507
28508 DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
28509 (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
28510
28511 DUK_ASSERT(fill_end - fill_offset >= 0);
28512 DUK_ASSERT(h_this->buf != NULL);
28513
28514 p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
28515 fill_length = (duk_size_t) (fill_end - fill_offset);
28516 if (fill_str_len == 1) {
28517 /* Handle single character fills as memset() even when
28518 * the fill data comes from a one-char argument.
28519 */
28520 duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
28521 } else if (fill_str_len > 1) {
28522 duk_size_t i, n, t;
28523
28524 for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) {
28525 p[i] = fill_str_ptr[t++];
28526 if (t >= fill_str_len) {
28527 t = 0;
28528 }
28529 }
28530 } else {
28531 DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
28532 }
28533
28534 /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
28535 duk_push_this(thr);
28536 return 1;
28537}
28538#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28539
28540/*
28541 * Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
28542 */
28543
28544#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28545DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
28546 duk_hbufobj *h_this;
28547 duk_uint_t offset;
28548 duk_uint_t length;
28549 const duk_uint8_t *str_data;
28550 duk_size_t str_len;
28551
28552 /* XXX: very inefficient support for plain buffers */
28553 h_this = duk__require_bufobj_this(thr);
28554 DUK_ASSERT(h_this != NULL);
28555
28556 /* Argument must be a string, e.g. a buffer is not allowed. */
28557 str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len);
28558
28559 duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
28560 DUK_ASSERT(offset <= h_this->length);
28561 DUK_ASSERT(offset + length <= h_this->length);
28562
28563 /* XXX: encoding is ignored now. */
28564
28565 if (length > str_len) {
28566 length = (duk_uint_t) str_len;
28567 }
28568
28569 if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
28570 /* Cannot overlap. */
28571 duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
28572 (const void *) str_data,
28573 (size_t) length);
28574 } else {
28575 DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
28576 }
28577
28578 duk_push_uint(thr, length);
28579 return 1;
28580}
28581#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28582
28583/*
28584 * Node.js Buffer.prototype.copy()
28585 */
28586
28587#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28588DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
28589 duk_hbufobj *h_this;
28590 duk_hbufobj *h_bufarg;
28591 duk_int_t source_length;
28592 duk_int_t target_length;
28593 duk_int_t target_start, source_start, source_end;
28594 duk_uint_t target_ustart, source_ustart, source_uend;
28595 duk_uint_t copy_size = 0;
28596
28597 /* [ targetBuffer targetStart sourceStart sourceEnd ] */
28598
28599 h_this = duk__require_bufobj_this(thr);
28600 h_bufarg = duk__require_bufobj_value(thr, 0);
28601 DUK_ASSERT(h_this != NULL);
28602 DUK_ASSERT(h_bufarg != NULL);
28603 source_length = (duk_int_t) h_this->length;
28604 target_length = (duk_int_t) h_bufarg->length;
28605
28606 target_start = duk_to_int(thr, 1);
28607 source_start = duk_to_int(thr, 2);
28608 if (duk_is_undefined(thr, 3)) {
28609 source_end = source_length;
28610 } else {
28611 source_end = duk_to_int(thr, 3);
28612 }
28613
28614 DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
28615 "source_start=%ld, source_end=%ld, source_length=%ld",
28616 (long) target_start, (long) h_bufarg->length,
28617 (long) source_start, (long) source_end, (long) source_length));
28618
28619 /* This behavior mostly mimics Node.js now. */
28620
28621 if (source_start < 0 || source_end < 0 || target_start < 0) {
28622 /* Negative offsets cause a RangeError. */
28623 goto fail_bounds;
28624 }
28625 source_ustart = (duk_uint_t) source_start;
28626 source_uend = (duk_uint_t) source_end;
28627 target_ustart = (duk_uint_t) target_start;
28628 if (source_ustart >= source_uend || /* crossed offsets or zero size */
28629 source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */
28630 target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */
28631 goto silent_ignore;
28632 }
28633 if (source_uend >= (duk_uint_t) source_length) {
28634 /* Source end clamped silently to available length. */
28635 source_uend = (duk_uint_t) source_length;
28636 }
28637 copy_size = source_uend - source_ustart;
28638 if (target_ustart + copy_size > (duk_uint_t) target_length) {
28639 /* Clamp to target's end if too long.
28640 *
28641 * NOTE: there's no overflow possibility in the comparison;
28642 * both target_ustart and copy_size are >= 0 and based on
28643 * values in duk_int_t range. Adding them as duk_uint_t
28644 * values is then guaranteed not to overflow.
28645 */
28646 DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */
28647 DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */
28648 copy_size = (duk_uint_t) target_length - target_ustart;
28649 }
28650
28651 DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
28652 (unsigned long) target_ustart, (unsigned long) source_ustart,
28653 (unsigned long) copy_size));
28654
28655 DUK_ASSERT(copy_size >= 1);
28656 DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
28657 DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
28658 DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
28659 DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
28660
28661 /* Ensure copy is covered by underlying buffers. */
28662 DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
28663 DUK_ASSERT(h_this->buf != NULL); /* length check */
28664 if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
28665 DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
28666 /* Must use memmove() because copy area may overlap (source and target
28667 * buffer may be the same, or from different slices.
28668 */
28669 duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
28670 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
28671 (size_t) copy_size);
28672 } else {
28673 DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
28674 }
28675
28676 silent_ignore:
28677 /* Return value is like write(), number of bytes written.
28678 * The return value matters because of code like:
28679 * "off += buf.copy(...)".
28680 */
28681 duk_push_uint(thr, copy_size);
28682 return 1;
28683
28684 fail_bounds:
28685 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28686}
28687#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28688
28689/*
28690 * TypedArray.prototype.set()
28691 *
28692 * TypedArray set() is pretty interesting to implement because:
28693 *
28694 * - The source argument may be a plain array or a typedarray. If the
28695 * source is a TypedArray, values are decoded and re-encoded into the
28696 * target (not as a plain byte copy). This may happen even when the
28697 * element byte size is the same, e.g. integer values may be re-encoded
28698 * into floats.
28699 *
28700 * - Source and target may refer to the same underlying buffer, so that
28701 * the set() operation may overlap. The specification requires that this
28702 * must work as if a copy was made before the operation. Note that this
28703 * is NOT a simple memmove() situation because the source and target
28704 * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
28705 * expand to a 16-byte target (Uint32Array) so that the target overlaps
28706 * the source both from beginning and the end (unlike in typical memmove).
28707 *
28708 * - Even if 'buf' pointers of the source and target differ, there's no
28709 * guarantee that their memory areas don't overlap. This may be the
28710 * case with external buffers.
28711 *
28712 * Even so, it is nice to optimize for the common case:
28713 *
28714 * - Source and target separate buffers or non-overlapping.
28715 *
28716 * - Source and target have a compatible type so that a plain byte copy
28717 * is possible. Note that while e.g. uint8 and int8 are compatible
28718 * (coercion one way or another doesn't change the byte representation),
28719 * e.g. int8 and uint8clamped are NOT compatible when writing int8
28720 * values into uint8clamped typedarray (-1 would clamp to 0 for instance).
28721 *
28722 * See test-bi-typedarray-proto-set.js.
28723 */
28724
28725#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28726DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
28727 duk_hbufobj *h_this;
28728 duk_hobject *h_obj;
28729 duk_uarridx_t i, n;
28730 duk_int_t offset_signed;
28731 duk_uint_t offset_elems;
28732 duk_uint_t offset_bytes;
28733
28734 h_this = duk__require_bufobj_this(thr);
28735 DUK_ASSERT(h_this != NULL);
28736 DUK_HBUFOBJ_ASSERT_VALID(h_this);
28737
28738 if (h_this->buf == NULL) {
28739 DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
28740 return 0;
28741 }
28742
28743 duk_hbufobj_promote_plain(thr, 0);
28744 h_obj = duk_require_hobject(thr, 0);
28745
28746 /* XXX: V8 throws a TypeError for negative values. Would it
28747 * be more useful to interpret negative offsets here from the
28748 * end of the buffer too?
28749 */
28750 offset_signed = duk_to_int(thr, 1);
28751 if (offset_signed < 0) {
28752 /* For some reason this is a TypeError (at least in V8). */
28753 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28754 }
28755 offset_elems = (duk_uint_t) offset_signed;
28756 offset_bytes = offset_elems << h_this->shift;
28757 if ((offset_bytes >> h_this->shift) != offset_elems) {
28758 /* Byte length would overflow. */
28759 /* XXX: easier check with less code? */
28760 goto fail_args;
28761 }
28762 if (offset_bytes > h_this->length) {
28763 /* Equality may be OK but >length not. Checking
28764 * this explicitly avoids some overflow cases
28765 * below.
28766 */
28767 goto fail_args;
28768 }
28769 DUK_ASSERT(offset_bytes <= h_this->length);
28770
28771 /* Fast path: source is a TypedArray (or any bufobj). */
28772
28773 if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
28774 duk_hbufobj *h_bufarg;
28775#if !defined(DUK_USE_PREFER_SIZE)
28776 duk_uint16_t comp_mask;
28777#endif
28778 duk_small_int_t no_overlap = 0;
28779 duk_uint_t src_length;
28780 duk_uint_t dst_length;
28781 duk_uint_t dst_length_elems;
28782 duk_uint8_t *p_src_base;
28783 duk_uint8_t *p_src_end;
28784 duk_uint8_t *p_src;
28785 duk_uint8_t *p_dst_base;
28786 duk_uint8_t *p_dst;
28787 duk_small_uint_t src_elem_size;
28788 duk_small_uint_t dst_elem_size;
28789
28790 h_bufarg = (duk_hbufobj *) h_obj;
28791 DUK_HBUFOBJ_ASSERT_VALID(h_bufarg);
28792
28793 if (h_bufarg->buf == NULL) {
28794 DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
28795 return 0;
28796 }
28797
28798 /* Nominal size check. */
28799 src_length = h_bufarg->length; /* bytes in source */
28800 dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */
28801 dst_length = dst_length_elems << h_this->shift; /* bytes in dest */
28802 if ((dst_length >> h_this->shift) != dst_length_elems) {
28803 /* Byte length would overflow. */
28804 /* XXX: easier check with less code? */
28805 goto fail_args;
28806 }
28807 DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
28808 (long) src_length, (long) dst_length));
28809 DUK_ASSERT(offset_bytes <= h_this->length);
28810 if (dst_length > h_this->length - offset_bytes) {
28811 /* Overflow not an issue because subtraction is used on the right
28812 * side and guaranteed to be >= 0.
28813 */
28814 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
28815 goto fail_args;
28816 }
28817 if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
28818 DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
28819 return 0;
28820 }
28821
28822 p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
28823 p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
28824
28825 /* Check actual underlying buffers for validity and that they
28826 * cover the copy. No side effects are allowed after the check
28827 * so that the validity status doesn't change.
28828 */
28829 if (!DUK_HBUFOBJ_VALID_SLICE(h_this) ||
28830 !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
28831 /* The condition could be more narrow and check for the
28832 * copy area only, but there's no need for fine grained
28833 * behavior when the underlying buffer is misconfigured.
28834 */
28835 DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
28836 return 0;
28837 }
28838
28839 /* We want to do a straight memory copy if possible: this is
28840 * an important operation because .set() is the TypedArray
28841 * way to copy chunks of memory. However, because set()
28842 * conceptually works in terms of elements, not all views are
28843 * compatible with direct byte copying.
28844 *
28845 * If we do manage a direct copy, the "overlap issue" handled
28846 * below can just be solved using memmove() because the source
28847 * and destination element sizes are necessarily equal.
28848 */
28849
28850#if !defined(DUK_USE_PREFER_SIZE)
28851 DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
28852 comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
28853 if (comp_mask & (1 << h_bufarg->elem_type)) {
28854 DUK_ASSERT(src_length == dst_length);
28855
28856 DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
28857 duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
28858 return 0;
28859 }
28860 DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
28861#endif /* !DUK_USE_PREFER_SIZE */
28862
28863 /* We want to avoid making a copy to process set() but that's
28864 * not always possible: the source and the target may overlap
28865 * and because element sizes are different, the overlap cannot
28866 * always be handled with a memmove() or choosing the copy
28867 * direction in a certain way. For example, if source type is
28868 * uint8 and target type is uint32, the target area may exceed
28869 * the source area from both ends!
28870 *
28871 * Note that because external buffers may point to the same
28872 * memory areas, we must ultimately make this check using
28873 * pointers.
28874 *
28875 * NOTE: careful with side effects: any side effect may cause
28876 * a buffer resize (or external buffer pointer/length update)!
28877 */
28878
28879 DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
28880 "p_dst_base=%p, dst_length=%ld",
28881 (void *) p_src_base, (long) src_length,
28882 (void *) p_dst_base, (long) dst_length));
28883
28884 if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */
28885 p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */
28886 no_overlap = 1;
28887 }
28888
28889 if (!no_overlap) {
28890 /* There's overlap: the desired end result is that
28891 * conceptually a copy is made to avoid "trampling"
28892 * of source data by destination writes. We make
28893 * an actual temporary copy to handle this case.
28894 */
28895 duk_uint8_t *p_src_copy;
28896
28897 DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
28898 p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
28899 DUK_ASSERT(p_src_copy != NULL);
28900 duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
28901
28902 p_src_base = p_src_copy; /* use p_src_base from now on */
28903 }
28904 /* Value stack intentionally mixed size here. */
28905
28906 DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
28907 "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
28908 (void *) p_src_base, (long) src_length,
28909 (void *) p_dst_base, (long) dst_length,
28910 (long) duk_get_top(thr)));
28911
28912 /* Ready to make the copy. We must proceed element by element
28913 * and must avoid any side effects that might cause the buffer
28914 * validity check above to become invalid.
28915 *
28916 * Although we work through the value stack here, only plain
28917 * numbers are handled which should be side effect safe.
28918 */
28919
28920 src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
28921 dst_elem_size = (duk_small_uint_t) (1U << h_this->shift);
28922 p_src = p_src_base;
28923 p_dst = p_dst_base;
28924 p_src_end = p_src_base + src_length;
28925
28926 while (p_src != p_src_end) {
28927 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
28928 "p_src=%p, p_src_end=%p, p_dst=%p",
28929 (void *) p_src, (void *) p_src_end, (void *) p_dst));
28930 /* A validated read() is always a number, so it's write coercion
28931 * is always side effect free an won't invalidate pointers etc.
28932 */
28933 duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
28934 duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size);
28935 duk_pop(thr);
28936 p_src += src_elem_size;
28937 p_dst += dst_elem_size;
28938 }
28939
28940 return 0;
28941 } else {
28942 /* Slow path: quite slow, but we save space by using the property code
28943 * to write coerce target values. We don't need to worry about overlap
28944 * here because the source is not a TypedArray.
28945 *
28946 * We could use the bufobj write coercion helper but since the
28947 * property read may have arbitrary side effects, full validity checks
28948 * would be needed for every element anyway.
28949 */
28950
28951 n = (duk_uarridx_t) duk_get_length(thr, 0);
28952 DUK_ASSERT(offset_bytes <= h_this->length);
28953 if ((n << h_this->shift) > h_this->length - offset_bytes) {
28954 /* Overflow not an issue because subtraction is used on the right
28955 * side and guaranteed to be >= 0.
28956 */
28957 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
28958 goto fail_args;
28959 }
28960
28961 /* There's no need to check for buffer validity status for the
28962 * target here: the property access code will do that for each
28963 * element. Moreover, if we did check the validity here, side
28964 * effects from reading the source argument might invalidate
28965 * the results anyway.
28966 */
28967
28968 DUK_ASSERT_TOP(thr, 2);
28969 duk_push_this(thr);
28970
28971 for (i = 0; i < n; i++) {
28972 duk_get_prop_index(thr, 0, i);
28973 duk_put_prop_index(thr, 2, offset_elems + i);
28974 }
28975 }
28976
28977 return 0;
28978
28979 fail_args:
28980 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28981}
28982#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28983
28984/*
28985 * Node.js Buffer.prototype.slice([start], [end])
28986 * ArrayBuffer.prototype.slice(begin, [end])
28987 * TypedArray.prototype.subarray(begin, [end])
28988 *
28989 * The API calls are almost identical; negative indices are counted from end
28990 * of buffer, and final indices are clamped (allowing crossed indices). Main
28991 * differences:
28992 *
28993 * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
28994 * views, ArrayBuffer .slice() creates a copy
28995 *
28996 * - Resulting object has a different class and prototype depending on the
28997 * call (or 'this' argument)
28998 *
28999 * - TypedArray .subarray() arguments are element indices, not byte offsets
29000 *
29001 * - Plain buffer argument creates a plain buffer slice
29002 */
29003
29004#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29005DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) {
29006 duk_int_t start_offset, end_offset;
29007 duk_uint_t slice_length;
29008 duk_uint8_t *p_copy;
29009 duk_size_t copy_length;
29010
29011 duk__clamp_startend_negidx_shifted(thr,
29012 (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
29013 0 /*buffer_shift*/,
29014 0 /*idx_start*/,
29015 1 /*idx_end*/,
29016 &start_offset,
29017 &end_offset);
29018 DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val));
29019 DUK_ASSERT(start_offset >= 0);
29020 DUK_ASSERT(end_offset >= start_offset);
29021 slice_length = (duk_uint_t) (end_offset - start_offset);
29022
29023 p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length);
29024 DUK_ASSERT(p_copy != NULL);
29025 copy_length = slice_length;
29026
29027 duk_memcpy_unsafe((void *) p_copy,
29028 (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
29029 copy_length);
29030}
29031#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29032
29033#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29034/* Shared helper for slice/subarray operation.
29035 * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
29036 */
29037DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
29038 duk_small_int_t magic;
29039 duk_small_uint_t res_class_num;
29040 duk_small_int_t res_proto_bidx;
29041 duk_hbufobj *h_this;
29042 duk_hbufobj *h_bufobj;
29043 duk_hbuffer *h_val;
29044 duk_int_t start_offset, end_offset;
29045 duk_uint_t slice_length;
29046 duk_tval *tv;
29047
29048 /* [ start end ] */
29049
29050 magic = duk_get_current_magic(thr);
29051
29052 tv = duk_get_borrowed_this_tval(thr);
29053 DUK_ASSERT(tv != NULL);
29054
29055 if (DUK_TVAL_IS_BUFFER(tv)) {
29056 /* For plain buffers return a plain buffer slice. */
29057 h_val = DUK_TVAL_GET_BUFFER(tv);
29058 DUK_ASSERT(h_val != NULL);
29059
29060 if (magic & 0x02) {
29061 /* Make copy: ArrayBuffer.prototype.slice() uses this. */
29062 duk__arraybuffer_plain_slice(thr, h_val);
29063 return 1;
29064 } else {
29065 /* View into existing buffer: cannot be done if the
29066 * result is a plain buffer because there's no slice
29067 * info. So return an ArrayBuffer instance; coerce
29068 * the 'this' binding into an object and behave as if
29069 * the original call was for an Object-coerced plain
29070 * buffer (handled automatically by duk__require_bufobj_this()).
29071 */
29072
29073 DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object"));
29074 /* fall through */
29075 }
29076 }
29077 tv = NULL; /* No longer valid nor needed. */
29078
29079 h_this = duk__require_bufobj_this(thr);
29080
29081 /* Slice offsets are element (not byte) offsets, which only matters
29082 * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
29083 * zero so byte and element offsets are the same. Negative indices
29084 * are counted from end of slice, crossed indices are allowed (and
29085 * result in zero length result), and final values are clamped
29086 * against the current slice. There's intentionally no check
29087 * against the underlying buffer here.
29088 */
29089
29090 duk__clamp_startend_negidx_shifted(thr,
29091 (duk_int_t) h_this->length,
29092 (duk_uint8_t) h_this->shift,
29093 0 /*idx_start*/,
29094 1 /*idx_end*/,
29095 &start_offset,
29096 &end_offset);
29097 DUK_ASSERT(end_offset >= start_offset);
29098 DUK_ASSERT(start_offset >= 0);
29099 DUK_ASSERT(end_offset >= 0);
29100 slice_length = (duk_uint_t) (end_offset - start_offset);
29101
29102 /* The resulting buffer object gets the same class and prototype as
29103 * the buffer in 'this', e.g. if the input is a Uint8Array the
29104 * result is a Uint8Array; if the input is a Float32Array, the
29105 * result is a Float32Array. The result internal prototype should
29106 * be the default prototype for the class (e.g. initial value of
29107 * Uint8Array.prototype), not copied from the argument (Duktape 1.x
29108 * did that).
29109 *
29110 * Node.js Buffers have special handling: they're Uint8Arrays as far
29111 * as the internal class is concerned, so the new Buffer should also
29112 * be an Uint8Array but inherit from Buffer.prototype.
29113 */
29114 res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
29115 DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */
29116 DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX);
29117 res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN];
29118 if (magic & 0x04) {
29119 res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
29120 }
29121 h_bufobj = duk_push_bufobj_raw(thr,
29122 DUK_HOBJECT_FLAG_EXTENSIBLE |
29123 DUK_HOBJECT_FLAG_BUFOBJ |
29124 DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
29125 res_proto_bidx);
29126 DUK_ASSERT(h_bufobj != NULL);
29127
29128 DUK_ASSERT(h_bufobj->length == 0);
29129 h_bufobj->shift = h_this->shift; /* inherit */
29130 h_bufobj->elem_type = h_this->elem_type; /* inherit */
29131 h_bufobj->is_typedarray = magic & 0x01;
29132 DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1);
29133
29134 h_val = h_this->buf;
29135 if (h_val == NULL) {
29136 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
29137 }
29138
29139 if (magic & 0x02) {
29140 /* non-zero: make copy */
29141 duk_uint8_t *p_copy;
29142 duk_size_t copy_length;
29143
29144 p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
29145 DUK_ASSERT(p_copy != NULL);
29146
29147 /* Copy slice, respecting underlying buffer limits; remainder
29148 * is left as zero.
29149 */
29150 copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
29151 duk_memcpy_unsafe((void *) p_copy,
29152 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
29153 copy_length);
29154
29155 h_val = duk_known_hbuffer(thr, -1);
29156
29157 h_bufobj->buf = h_val;
29158 DUK_HBUFFER_INCREF(thr, h_val);
29159 h_bufobj->length = slice_length;
29160 DUK_ASSERT(h_bufobj->offset == 0);
29161
29162 duk_pop(thr); /* reachable so pop OK */
29163 } else {
29164 h_bufobj->buf = h_val;
29165 DUK_HBUFFER_INCREF(thr, h_val);
29166 h_bufobj->length = slice_length;
29167 h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset;
29168
29169 /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
29170 *
29171 * XXX: limit copy only for TypedArray classes specifically?
29172 */
29173
29174 DUK_ASSERT(h_bufobj->buf_prop == NULL);
29175 h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */
29176 DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop);
29177 }
29178 /* unbalanced stack on purpose */
29179
29180 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
29181 return 1;
29182}
29183#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29184
29185/*
29186 * Node.js Buffer.isEncoding()
29187 */
29188
29189#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29190DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) {
29191 const char *encoding;
29192
29193 /* only accept lowercase 'utf8' now. */
29194
29195 encoding = duk_to_string(thr, 0);
29196 DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */
29197 duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0);
29198 return 1;
29199}
29200#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29201
29202/*
29203 * Node.js Buffer.isBuffer()
29204 */
29205
29206#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29207DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) {
29208 duk_hobject *h;
29209 duk_hobject *h_proto;
29210 duk_bool_t ret = 0;
29211
29212 DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */
29213 h = duk_get_hobject(thr, 0);
29214 if (h != NULL) {
29215 h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
29216 DUK_ASSERT(h_proto != NULL);
29217
29218 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
29219 if (h != NULL) {
29220 ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
29221 }
29222 }
29223
29224 duk_push_boolean(thr, ret);
29225 return 1;
29226}
29227#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29228
29229/*
29230 * Node.js Buffer.byteLength()
29231 */
29232
29233#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29234DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) {
29235 const char *str;
29236 duk_size_t len;
29237
29238 /* At the moment Buffer(<str>) will just use the string bytes as
29239 * is (ignoring encoding), so we return the string length here
29240 * unconditionally.
29241 */
29242
29243 /* XXX: to be revised; Old Node.js behavior just coerces any buffer
29244 * values to string:
29245 * $ node
29246 * > Buffer.byteLength(new Uint32Array(10))
29247 * 20
29248 * > Buffer.byteLength(new Uint32Array(100))
29249 * 20
29250 * (The 20 comes from '[object Uint32Array]'.length
29251 */
29252
29253 str = duk_to_lstring(thr, 0, &len);
29254 DUK_UNREF(str);
29255 duk_push_size_t(thr, len);
29256 return 1;
29257}
29258#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29259
29260/*
29261 * Node.js Buffer.concat()
29262 */
29263
29264#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29265DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
29266 duk_hobject *h_arg;
29267 duk_uint_t total_length;
29268 duk_hbufobj *h_bufobj;
29269 duk_hbufobj *h_bufres;
29270 duk_hbuffer *h_val;
29271 duk_uint_t i, n;
29272 duk_uint8_t *p;
29273 duk_size_t space_left;
29274 duk_size_t copy_size;
29275
29276 /* Node.js accepts only actual Arrays. */
29277 h_arg = duk_require_hobject(thr, 0);
29278 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
29279 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
29280 }
29281
29282 /* Compute result length and validate argument buffers. */
29283 n = (duk_uint_t) duk_get_length(thr, 0);
29284 total_length = 0;
29285 for (i = 0; i < n; i++) {
29286 /* Neutered checks not necessary here: neutered buffers have
29287 * zero 'length' so we'll effectively skip them.
29288 */
29289 DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */
29290 duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
29291 h_bufobj = duk__require_bufobj_value(thr, 2);
29292 DUK_ASSERT(h_bufobj != NULL);
29293 total_length += h_bufobj->length;
29294 if (DUK_UNLIKELY(total_length < h_bufobj->length)) {
29295 DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */
29296 }
29297 duk_pop(thr);
29298 }
29299 /* In Node.js v0.12.1 a 1-element array is special and won't create a
29300 * copy, this was fixed later so an explicit check no longer needed.
29301 */
29302
29303 /* User totalLength overrides a computed length, but we'll check
29304 * every copy in the copy loop. Note that duk_to_int() can
29305 * technically have arbitrary side effects so we need to recheck
29306 * the buffers in the copy loop.
29307 */
29308 if (!duk_is_undefined(thr, 1) && n > 0) {
29309 /* For n == 0, Node.js ignores totalLength argument and
29310 * returns a zero length buffer.
29311 */
29312 duk_int_t total_length_signed;
29313 total_length_signed = duk_to_int(thr, 1);
29314 if (total_length_signed < 0) {
29315 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
29316 }
29317 total_length = (duk_uint_t) total_length_signed;
29318 }
29319
29320 h_bufres = duk_push_bufobj_raw(thr,
29321 DUK_HOBJECT_FLAG_EXTENSIBLE |
29322 DUK_HOBJECT_FLAG_BUFOBJ |
29323 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
29324 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
29325 DUK_ASSERT(h_bufres != NULL);
29326
29327 p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */
29328 DUK_ASSERT(p != NULL);
29329 space_left = (duk_size_t) total_length;
29330
29331 for (i = 0; i < n; i++) {
29332 DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */
29333
29334 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
29335 h_bufobj = duk__require_bufobj_value(thr, 4);
29336 DUK_ASSERT(h_bufobj != NULL);
29337
29338 copy_size = h_bufobj->length;
29339 if (copy_size > space_left) {
29340 copy_size = space_left;
29341 }
29342
29343 if (h_bufobj->buf != NULL &&
29344 DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
29345 duk_memcpy_unsafe((void *) p,
29346 (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
29347 copy_size);
29348 } else {
29349 /* Just skip, leaving zeroes in the result. */
29350 ;
29351 }
29352 p += copy_size;
29353 space_left -= copy_size;
29354
29355 duk_pop(thr);
29356 }
29357
29358 h_val = duk_known_hbuffer(thr, -1);
29359
29360 duk__set_bufobj_buffer(thr, h_bufres, h_val);
29361 h_bufres->is_typedarray = 1;
29362 DUK_HBUFOBJ_ASSERT_VALID(h_bufres);
29363
29364 duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */
29365
29366 return 1; /* return h_bufres */
29367}
29368#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29369
29370/*
29371 * Shared readfield and writefield methods
29372 *
29373 * The readfield/writefield methods need support for endianness and field
29374 * types. All offsets are byte based so no offset shifting is needed.
29375 */
29376
29377#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29378/* Format of magic, bits:
29379 * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
29380 * 3: endianness: 0=little, 1=big
29381 * 4: signed: 1=yes, 0=no
29382 * 5: typedarray: 1=yes, 0=no
29383 */
29384#define DUK__FLD_8BIT 0
29385#define DUK__FLD_16BIT 1
29386#define DUK__FLD_32BIT 2
29387#define DUK__FLD_FLOAT 3
29388#define DUK__FLD_DOUBLE 4
29389#define DUK__FLD_VARINT 5
29390#define DUK__FLD_BIGENDIAN (1 << 3)
29391#define DUK__FLD_SIGNED (1 << 4)
29392#define DUK__FLD_TYPEDARRAY (1 << 5)
29393
29394/* XXX: split into separate functions for each field type? */
29395DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
29396 duk_small_uint_t magic = (duk_small_uint_t) duk_get_current_magic(thr);
29397 duk_small_uint_t magic_ftype;
29398 duk_small_uint_t magic_bigendian;
29399 duk_small_uint_t magic_signed;
29400 duk_small_uint_t magic_typedarray;
29401 duk_small_uint_t endswap;
29402 duk_hbufobj *h_this;
29403 duk_bool_t no_assert;
29404 duk_int_t offset_signed;
29405 duk_uint_t offset;
29406 duk_uint_t buffer_length;
29407 duk_uint_t check_length;
29408 duk_uint8_t *buf;
29409 duk_double_union du;
29410
29411 magic_ftype = magic & 0x0007U;
29412 magic_bigendian = magic & 0x0008U;
29413 magic_signed = magic & 0x0010U;
29414 magic_typedarray = magic & 0x0020U;
29415
29416 h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
29417 DUK_ASSERT(h_this != NULL);
29418 buffer_length = h_this->length;
29419
29420 /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */
29421 /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
29422 /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
29423
29424 /* Handle TypedArray vs. Node.js Buffer arg differences */
29425 if (magic_typedarray) {
29426 no_assert = 0;
29427#if defined(DUK_USE_INTEGER_LE)
29428 endswap = !duk_to_boolean(thr, 1); /* 1=little endian */
29429#else
29430 endswap = duk_to_boolean(thr, 1); /* 1=little endian */
29431#endif
29432 } else {
29433 no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
29434#if defined(DUK_USE_INTEGER_LE)
29435 endswap = magic_bigendian;
29436#else
29437 endswap = !magic_bigendian;
29438#endif
29439 }
29440
29441 /* Offset is coerced first to signed integer range and then to unsigned.
29442 * This ensures we can add a small byte length (1-8) to the offset in
29443 * bound checks and not wrap.
29444 */
29445 offset_signed = duk_to_int(thr, 0);
29446 offset = (duk_uint_t) offset_signed;
29447 if (offset_signed < 0) {
29448 goto fail_bounds;
29449 }
29450
29451 DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
29452 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
29453 "endswap=%u",
29454 (long) buffer_length, (long) offset, (int) no_assert,
29455 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
29456 (int) (magic_signed >> 4), (int) endswap));
29457
29458 /* Update 'buffer_length' to be the effective, safe limit which
29459 * takes into account the underlying buffer. This value will be
29460 * potentially invalidated by any side effect.
29461 */
29462 check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
29463 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
29464 (long) buffer_length, (long) check_length));
29465
29466 if (h_this->buf) {
29467 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
29468 } else {
29469 /* Neutered. We could go into the switch-case safely with
29470 * buf == NULL because check_length == 0. To avoid scanbuild
29471 * warnings, fail directly instead.
29472 */
29473 DUK_ASSERT(check_length == 0);
29474 goto fail_neutered;
29475 }
29476 DUK_ASSERT(buf != NULL);
29477
29478 switch (magic_ftype) {
29479 case DUK__FLD_8BIT: {
29480 duk_uint8_t tmp;
29481 if (offset + 1U > check_length) {
29482 goto fail_bounds;
29483 }
29484 tmp = buf[offset];
29485 if (magic_signed) {
29486 duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp));
29487 } else {
29488 duk_push_uint(thr, (duk_uint_t) tmp);
29489 }
29490 break;
29491 }
29492 case DUK__FLD_16BIT: {
29493 duk_uint16_t tmp;
29494 if (offset + 2U > check_length) {
29495 goto fail_bounds;
29496 }
29497 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 2);
29498 tmp = du.us[0];
29499 if (endswap) {
29500 tmp = DUK_BSWAP16(tmp);
29501 }
29502 if (magic_signed) {
29503 duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp));
29504 } else {
29505 duk_push_uint(thr, (duk_uint_t) tmp);
29506 }
29507 break;
29508 }
29509 case DUK__FLD_32BIT: {
29510 duk_uint32_t tmp;
29511 if (offset + 4U > check_length) {
29512 goto fail_bounds;
29513 }
29514 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
29515 tmp = du.ui[0];
29516 if (endswap) {
29517 tmp = DUK_BSWAP32(tmp);
29518 }
29519 if (magic_signed) {
29520 duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp));
29521 } else {
29522 duk_push_uint(thr, (duk_uint_t) tmp);
29523 }
29524 break;
29525 }
29526 case DUK__FLD_FLOAT: {
29527 duk_uint32_t tmp;
29528 if (offset + 4U > check_length) {
29529 goto fail_bounds;
29530 }
29531 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
29532 if (endswap) {
29533 tmp = du.ui[0];
29534 tmp = DUK_BSWAP32(tmp);
29535 du.ui[0] = tmp;
29536 }
29537 duk_push_number(thr, (duk_double_t) du.f[0]);
29538 break;
29539 }
29540 case DUK__FLD_DOUBLE: {
29541 if (offset + 8U > check_length) {
29542 goto fail_bounds;
29543 }
29544 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 8);
29545 if (endswap) {
29546 DUK_DBLUNION_BSWAP64(&du);
29547 }
29548 duk_push_number(thr, (duk_double_t) du.d);
29549 break;
29550 }
29551 case DUK__FLD_VARINT: {
29552 /* Node.js Buffer variable width integer field. We don't really
29553 * care about speed here, so aim for shortest algorithm.
29554 */
29555 duk_int_t field_bytelen;
29556 duk_int_t i, i_step, i_end;
29557#if defined(DUK_USE_64BIT_OPS)
29558 duk_int64_t tmp;
29559 duk_small_uint_t shift_tmp;
29560#else
29561 duk_double_t tmp;
29562 duk_small_int_t highbyte;
29563#endif
29564 const duk_uint8_t *p;
29565
29566 field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */
29567 if (field_bytelen < 1 || field_bytelen > 6) {
29568 goto fail_field_length;
29569 }
29570 if (offset + (duk_uint_t) field_bytelen > check_length) {
29571 goto fail_bounds;
29572 }
29573 p = (const duk_uint8_t *) (buf + offset);
29574
29575 /* Slow gathering of value using either 64-bit arithmetic
29576 * or IEEE doubles if 64-bit types not available. Handling
29577 * of negative numbers is a bit non-obvious in both cases.
29578 */
29579
29580 if (magic_bigendian) {
29581 /* Gather in big endian */
29582 i = 0;
29583 i_step = 1;
29584 i_end = field_bytelen; /* one i_step over */
29585 } else {
29586 /* Gather in little endian */
29587 i = field_bytelen - 1;
29588 i_step = -1;
29589 i_end = -1; /* one i_step over */
29590 }
29591
29592#if defined(DUK_USE_64BIT_OPS)
29593 tmp = 0;
29594 do {
29595 DUK_ASSERT(i >= 0 && i < field_bytelen);
29596 tmp = (tmp << 8) + (duk_int64_t) p[i];
29597 i += i_step;
29598 } while (i != i_end);
29599
29600 if (magic_signed) {
29601 /* Shift to sign extend. Left shift must be unsigned
29602 * to avoid undefined behavior; right shift must be
29603 * signed to sign extend properly.
29604 */
29605 shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
29606 tmp = (duk_int64_t) ((duk_uint64_t) tmp << shift_tmp) >> shift_tmp;
29607 }
29608
29609 duk_push_i64(thr, tmp);
29610#else
29611 highbyte = p[i];
29612 if (magic_signed && (highbyte & 0x80) != 0) {
29613 /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
29614 tmp = (duk_double_t) (highbyte - 256);
29615 } else {
29616 tmp = (duk_double_t) highbyte;
29617 }
29618 for (;;) {
29619 i += i_step;
29620 if (i == i_end) {
29621 break;
29622 }
29623 DUK_ASSERT(i >= 0 && i < field_bytelen);
29624 tmp = (tmp * 256.0) + (duk_double_t) p[i];
29625 }
29626
29627 duk_push_number(thr, tmp);
29628#endif
29629 break;
29630 }
29631 default: { /* should never happen but default here */
29632 goto fail_bounds;
29633 }
29634 }
29635
29636 return 1;
29637
29638 fail_neutered:
29639 fail_field_length:
29640 fail_bounds:
29641 if (no_assert) {
29642 /* Node.js return value for noAssert out-of-bounds reads is
29643 * usually (but not always) NaN. Return NaN consistently.
29644 */
29645 duk_push_nan(thr);
29646 return 1;
29647 }
29648 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
29649}
29650#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29651
29652#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29653/* XXX: split into separate functions for each field type? */
29654DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
29655 duk_small_uint_t magic = (duk_small_uint_t) duk_get_current_magic(thr);
29656 duk_small_uint_t magic_ftype;
29657 duk_small_uint_t magic_bigendian;
29658 duk_small_uint_t magic_signed;
29659 duk_small_uint_t magic_typedarray;
29660 duk_small_uint_t endswap;
29661 duk_hbufobj *h_this;
29662 duk_bool_t no_assert;
29663 duk_int_t offset_signed;
29664 duk_uint_t offset;
29665 duk_uint_t buffer_length;
29666 duk_uint_t check_length;
29667 duk_uint8_t *buf;
29668 duk_double_union du;
29669 duk_int_t nbytes = 0;
29670
29671 magic_ftype = magic & 0x0007U;
29672 magic_bigendian = magic & 0x0008U;
29673 magic_signed = magic & 0x0010U;
29674 magic_typedarray = magic & 0x0020U;
29675 DUK_UNREF(magic_signed);
29676
29677 h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */
29678 DUK_ASSERT(h_this != NULL);
29679 buffer_length = h_this->length;
29680
29681 /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */
29682 /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
29683 /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
29684
29685 /* Handle TypedArray vs. Node.js Buffer arg differences */
29686 if (magic_typedarray) {
29687 no_assert = 0;
29688#if defined(DUK_USE_INTEGER_LE)
29689 endswap = !duk_to_boolean(thr, 2); /* 1=little endian */
29690#else
29691 endswap = duk_to_boolean(thr, 2); /* 1=little endian */
29692#endif
29693 duk_swap(thr, 0, 1); /* offset/value order different from Node.js */
29694 } else {
29695 no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
29696#if defined(DUK_USE_INTEGER_LE)
29697 endswap = magic_bigendian;
29698#else
29699 endswap = !magic_bigendian;
29700#endif
29701 }
29702
29703 /* Offset is coerced first to signed integer range and then to unsigned.
29704 * This ensures we can add a small byte length (1-8) to the offset in
29705 * bound checks and not wrap.
29706 */
29707 offset_signed = duk_to_int(thr, 1);
29708 offset = (duk_uint_t) offset_signed;
29709
29710 /* We need 'nbytes' even for a failed offset; return value must be
29711 * (offset + nbytes) even when write fails due to invalid offset.
29712 */
29713 if (magic_ftype != DUK__FLD_VARINT) {
29714 DUK_ASSERT(magic_ftype < (duk_small_uint_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
29715 nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
29716 } else {
29717 nbytes = duk_get_int(thr, 2);
29718 if (nbytes < 1 || nbytes > 6) {
29719 goto fail_field_length;
29720 }
29721 }
29722 DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
29723
29724 /* Now we can check offset validity. */
29725 if (offset_signed < 0) {
29726 goto fail_bounds;
29727 }
29728
29729 DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
29730 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
29731 "endswap=%u",
29732 duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert,
29733 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
29734 (int) (magic_signed >> 4), (int) endswap));
29735
29736 /* Coerce value to a number before computing check_length, so that
29737 * the field type specific coercion below can't have side effects
29738 * that would invalidate check_length.
29739 */
29740 duk_to_number(thr, 0);
29741
29742 /* Update 'buffer_length' to be the effective, safe limit which
29743 * takes into account the underlying buffer. This value will be
29744 * potentially invalidated by any side effect.
29745 */
29746 check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
29747 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
29748 (long) buffer_length, (long) check_length));
29749
29750 if (h_this->buf) {
29751 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
29752 } else {
29753 /* Neutered. We could go into the switch-case safely with
29754 * buf == NULL because check_length == 0. To avoid scanbuild
29755 * warnings, fail directly instead.
29756 */
29757 DUK_ASSERT(check_length == 0);
29758 goto fail_neutered;
29759 }
29760 DUK_ASSERT(buf != NULL);
29761
29762 switch (magic_ftype) {
29763 case DUK__FLD_8BIT: {
29764 if (offset + 1U > check_length) {
29765 goto fail_bounds;
29766 }
29767 /* sign doesn't matter when writing */
29768 buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0);
29769 break;
29770 }
29771 case DUK__FLD_16BIT: {
29772 duk_uint16_t tmp;
29773 if (offset + 2U > check_length) {
29774 goto fail_bounds;
29775 }
29776 tmp = (duk_uint16_t) duk_to_uint32(thr, 0);
29777 if (endswap) {
29778 tmp = DUK_BSWAP16(tmp);
29779 }
29780 du.us[0] = tmp;
29781 /* sign doesn't matter when writing */
29782 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 2);
29783 break;
29784 }
29785 case DUK__FLD_32BIT: {
29786 duk_uint32_t tmp;
29787 if (offset + 4U > check_length) {
29788 goto fail_bounds;
29789 }
29790 tmp = (duk_uint32_t) duk_to_uint32(thr, 0);
29791 if (endswap) {
29792 tmp = DUK_BSWAP32(tmp);
29793 }
29794 du.ui[0] = tmp;
29795 /* sign doesn't matter when writing */
29796 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
29797 break;
29798 }
29799 case DUK__FLD_FLOAT: {
29800 duk_uint32_t tmp;
29801 if (offset + 4U > check_length) {
29802 goto fail_bounds;
29803 }
29804 du.f[0] = (duk_float_t) duk_to_number(thr, 0);
29805 if (endswap) {
29806 tmp = du.ui[0];
29807 tmp = DUK_BSWAP32(tmp);
29808 du.ui[0] = tmp;
29809 }
29810 /* sign doesn't matter when writing */
29811 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
29812 break;
29813 }
29814 case DUK__FLD_DOUBLE: {
29815 if (offset + 8U > check_length) {
29816 goto fail_bounds;
29817 }
29818 du.d = (duk_double_t) duk_to_number(thr, 0);
29819 if (endswap) {
29820 DUK_DBLUNION_BSWAP64(&du);
29821 }
29822 /* sign doesn't matter when writing */
29823 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 8);
29824 break;
29825 }
29826 case DUK__FLD_VARINT: {
29827 /* Node.js Buffer variable width integer field. We don't really
29828 * care about speed here, so aim for shortest algorithm.
29829 */
29830 duk_int_t field_bytelen;
29831 duk_int_t i, i_step, i_end;
29832#if defined(DUK_USE_64BIT_OPS)
29833 duk_int64_t tmp;
29834#else
29835 duk_double_t tmp;
29836#endif
29837 duk_uint8_t *p;
29838
29839 field_bytelen = (duk_int_t) nbytes;
29840 if (offset + (duk_uint_t) field_bytelen > check_length) {
29841 goto fail_bounds;
29842 }
29843
29844 /* Slow writing of value using either 64-bit arithmetic
29845 * or IEEE doubles if 64-bit types not available. There's
29846 * no special sign handling when writing varints.
29847 */
29848
29849 if (magic_bigendian) {
29850 /* Write in big endian */
29851 i = field_bytelen; /* one i_step added at top of loop */
29852 i_step = -1;
29853 i_end = 0;
29854 } else {
29855 /* Write in little endian */
29856 i = -1; /* one i_step added at top of loop */
29857 i_step = 1;
29858 i_end = field_bytelen - 1;
29859 }
29860
29861 /* XXX: The duk_to_number() cast followed by integer coercion
29862 * is platform specific so NaN, +/- Infinity, and out-of-bounds
29863 * values result in platform specific output now.
29864 * See: test-bi-nodejs-buffer-proto-varint-special.js
29865 */
29866
29867#if defined(DUK_USE_64BIT_OPS)
29868 tmp = (duk_int64_t) duk_to_number(thr, 0);
29869 p = (duk_uint8_t *) (buf + offset);
29870 do {
29871 i += i_step;
29872 DUK_ASSERT(i >= 0 && i < field_bytelen);
29873 p[i] = (duk_uint8_t) (tmp & 0xff);
29874 tmp = tmp >> 8; /* unnecessary shift for last byte */
29875 } while (i != i_end);
29876#else
29877 tmp = duk_to_number(thr, 0);
29878 p = (duk_uint8_t *) (buf + offset);
29879 do {
29880 i += i_step;
29881 tmp = DUK_FLOOR(tmp);
29882 DUK_ASSERT(i >= 0 && i < field_bytelen);
29883 p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
29884 tmp = tmp / 256.0; /* unnecessary div for last byte */
29885 } while (i != i_end);
29886#endif
29887 break;
29888 }
29889 default: { /* should never happen but default here */
29890 goto fail_bounds;
29891 }
29892 }
29893
29894 /* Node.js Buffer: return offset + #bytes written (i.e. next
29895 * write offset).
29896 */
29897 if (magic_typedarray) {
29898 /* For TypedArrays 'undefined' return value is specified
29899 * by ES2015 (matches V8).
29900 */
29901 return 0;
29902 }
29903 duk_push_uint(thr, offset + (duk_uint_t) nbytes);
29904 return 1;
29905
29906 fail_neutered:
29907 fail_field_length:
29908 fail_bounds:
29909 if (no_assert) {
29910 /* Node.js return value for failed writes is offset + #bytes
29911 * that would have been written.
29912 */
29913 /* XXX: for negative input offsets, 'offset' will be a large
29914 * positive value so the result here is confusing.
29915 */
29916 if (magic_typedarray) {
29917 return 0;
29918 }
29919 duk_push_uint(thr, offset + (duk_uint_t) nbytes);
29920 return 1;
29921 }
29922 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
29923}
29924#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
29925
29926/*
29927 * Accessors for .buffer, .byteLength, .byteOffset
29928 */
29929
29930#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29931DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) {
29932 duk_hbufobj *h_res;
29933
29934 h_res = duk_push_bufobj_raw(thr,
29935 DUK_HOBJECT_FLAG_EXTENSIBLE |
29936 DUK_HOBJECT_FLAG_BUFOBJ |
29937 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
29938 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
29939 DUK_ASSERT(h_res != NULL);
29940 DUK_UNREF(h_res);
29941
29942 duk__set_bufobj_buffer(thr, h_res, h_buf);
29943 DUK_HBUFOBJ_ASSERT_VALID(h_res);
29944 DUK_ASSERT(h_res->buf_prop == NULL);
29945 return h_res;
29946}
29947
29948DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
29949 duk_hbufobj *h_bufobj;
29950
29951 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
29952 DUK_ASSERT(h_bufobj != NULL);
29953 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
29954 DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer"));
29955 (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj);
29956 return 1;
29957 } else {
29958 if (h_bufobj->buf_prop == NULL &&
29959 DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER &&
29960 h_bufobj->buf != NULL) {
29961 duk_hbufobj *h_arrbuf;
29962
29963 DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView"));
29964 h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf);
29965
29966 if (h_bufobj->buf_prop == NULL) {
29967 /* Must recheck buf_prop, in case ArrayBuffer
29968 * alloc had a side effect which already filled
29969 * it!
29970 */
29971
29972 /* Set ArrayBuffer's .byteOffset and .byteLength based
29973 * on the view so that Arraybuffer[view.byteOffset]
29974 * matches view[0].
29975 */
29976 h_arrbuf->offset = 0;
29977 DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */
29978 h_arrbuf->length = h_bufobj->offset + h_bufobj->length;
29979 DUK_ASSERT(h_arrbuf->buf_prop == NULL);
29980
29981 DUK_ASSERT(h_bufobj->buf_prop == NULL);
29982 h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
29983 DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */
29984 }
29985
29986 /* Left on stack; pushed for the second time below (OK). */
29987 }
29988 if (h_bufobj->buf_prop) {
29989 duk_push_hobject(thr, h_bufobj->buf_prop);
29990 return 1;
29991 }
29992 }
29993 return 0;
29994}
29995
29996DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
29997 duk_hbufobj *h_bufobj;
29998
29999 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
30000 DUK_ASSERT(h_bufobj != NULL);
30001 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
30002 duk_push_uint(thr, 0);
30003 } else {
30004 /* If neutered must return 0; offset is zeroed during
30005 * neutering.
30006 */
30007 duk_push_uint(thr, h_bufobj->offset);
30008 }
30009 return 1;
30010}
30011
30012DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
30013 duk_hbufobj *h_bufobj;
30014
30015 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
30016 DUK_ASSERT(h_bufobj != NULL);
30017 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
30018 duk_hbuffer *h_buf;
30019
30020 h_buf = (duk_hbuffer *) h_bufobj;
30021 DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */
30022 duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
30023 } else {
30024 /* If neutered must return 0; length is zeroed during
30025 * neutering.
30026 */
30027 duk_push_uint(thr, h_bufobj->length);
30028 }
30029 return 1;
30030}
30031#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
30032/* No .buffer getter without ArrayBuffer support. */
30033#if 0
30034DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
30035 return 0;
30036}
30037#endif
30038
30039DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
30040 duk_push_uint(thr, 0);
30041 return 1;
30042}
30043
30044DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
30045 duk_hbuffer *h_buf;
30046
30047 /* XXX: helper? */
30048 duk_push_this(thr);
30049 h_buf = duk_require_hbuffer(thr, -1);
30050 duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf));
30051 return 1;
30052}
30053#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
30054
30055/* automatic undefs */
30056#undef DUK__BUFOBJ_FLAG_PROMOTE
30057#undef DUK__BUFOBJ_FLAG_THROW
30058#undef DUK__FLD_16BIT
30059#undef DUK__FLD_32BIT
30060#undef DUK__FLD_8BIT
30061#undef DUK__FLD_BIGENDIAN
30062#undef DUK__FLD_DOUBLE
30063#undef DUK__FLD_FLOAT
30064#undef DUK__FLD_SIGNED
30065#undef DUK__FLD_TYPEDARRAY
30066#undef DUK__FLD_VARINT
30067#line 1 "duk_bi_cbor.c"
30068/*
30069 * CBOR bindings.
30070 *
30071 * http://cbor.io/
30072 * https://tools.ietf.org/html/rfc7049
30073 */
30074
30075/* #include duk_internal.h -> already included */
30076
30077#if defined(DUK_USE_CBOR_SUPPORT)
30078
30079/* #define DUK_CBOR_STRESS */
30080
30081/* Default behavior for encoding strings: use CBOR text string if string
30082 * is UTF-8 compatible, otherwise use CBOR byte string. These defines
30083 * can be used to force either type for all strings. Using text strings
30084 * for non-UTF-8 data is technically invalid CBOR.
30085 */
30086/* #define DUK_CBOR_TEXT_STRINGS */
30087/* #define DUK_CBOR_BYTE_STRINGS */
30088
30089/* Misc. defines. */
30090/* #define DUK_CBOR_PREFER_SIZE */
30091/* #define DUK_CBOR_DOUBLE_AS_IS */
30092/* #define DUK_CBOR_DECODE_FASTPATH */
30093
30094typedef struct {
30095 duk_hthread *thr;
30096 duk_uint8_t *ptr;
30097 duk_uint8_t *buf;
30098 duk_uint8_t *buf_end;
30099 duk_size_t len;
30100 duk_idx_t idx_buf;
30101 duk_uint_t recursion_depth;
30102 duk_uint_t recursion_limit;
30103} duk_cbor_encode_context;
30104
30105typedef struct {
30106 duk_hthread *thr;
30107 const duk_uint8_t *buf;
30108 duk_size_t off;
30109 duk_size_t len;
30110 duk_uint_t recursion_depth;
30111 duk_uint_t recursion_limit;
30112} duk_cbor_decode_context;
30113
30114DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx);
30115DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx);
30116
30117/*
30118 * Misc
30119 */
30120
30121DUK_LOCAL duk_uint32_t duk__cbor_double_to_uint32(double d) {
30122 /* Out of range casts are undefined behavior, so caller must avoid. */
30123 DUK_ASSERT(d >= 0.0 && d <= 4294967295.0);
30124 return (duk_uint32_t) d;
30125}
30126
30127/*
30128 * Encoding
30129 */
30130
30131DUK_LOCAL void duk__cbor_encode_error(duk_cbor_encode_context *enc_ctx) {
30132 (void) duk_type_error(enc_ctx->thr, "cbor encode error");
30133}
30134
30135DUK_LOCAL void duk__cbor_encode_req_stack(duk_cbor_encode_context *enc_ctx) {
30136 duk_require_stack(enc_ctx->thr, 4);
30137}
30138
30139DUK_LOCAL void duk__cbor_encode_objarr_entry(duk_cbor_encode_context *enc_ctx) {
30140 duk_hthread *thr = enc_ctx->thr;
30141
30142 /* Native stack check in object/array recursion. */
30143 duk_native_stack_check(thr);
30144
30145 /* When working with deeply recursive structures, this is important
30146 * to ensure there's no effective depth limit.
30147 */
30148 duk__cbor_encode_req_stack(enc_ctx);
30149
30150 DUK_ASSERT(enc_ctx->recursion_depth <= enc_ctx->recursion_limit);
30151 if (enc_ctx->recursion_depth >= enc_ctx->recursion_limit) {
30152 DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT);
30153 DUK_WO_NORETURN(return;);
30154 }
30155 enc_ctx->recursion_depth++;
30156}
30157
30158DUK_LOCAL void duk__cbor_encode_objarr_exit(duk_cbor_encode_context *enc_ctx) {
30159 DUK_ASSERT(enc_ctx->recursion_depth > 0);
30160 enc_ctx->recursion_depth--;
30161}
30162
30163/* Check that a size_t is in uint32 range to avoid out-of-range casts. */
30164DUK_LOCAL void duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
30165 if (DUK_UNLIKELY(sizeof(duk_size_t) > sizeof(duk_uint32_t) && len > (duk_size_t) DUK_UINT32_MAX)) {
30166 duk__cbor_encode_error(enc_ctx);
30167 }
30168}
30169
30170DUK_LOCAL DUK_NOINLINE void duk__cbor_encode_ensure_slowpath(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
30171 duk_size_t oldlen;
30172 duk_size_t minlen;
30173 duk_size_t newlen;
30174 duk_uint8_t *p_new;
30175 duk_size_t old_data_len;
30176
30177 DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf);
30178 DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->ptr);
30179 DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->buf);
30180
30181 /* Overflow check.
30182 *
30183 * Limit example: 0xffffffffUL / 2U = 0x7fffffffUL, we reject >= 0x80000000UL.
30184 */
30185 oldlen = enc_ctx->len;
30186 minlen = oldlen + len;
30187 if (DUK_UNLIKELY(oldlen > DUK_SIZE_MAX / 2U || minlen < oldlen)) {
30188 duk__cbor_encode_error(enc_ctx);
30189 }
30190
30191#if defined(DUK_CBOR_STRESS)
30192 newlen = oldlen + 1U;
30193#else
30194 newlen = oldlen * 2U;
30195#endif
30196 DUK_ASSERT(newlen >= oldlen);
30197
30198 if (minlen > newlen) {
30199 newlen = minlen;
30200 }
30201 DUK_ASSERT(newlen >= oldlen);
30202 DUK_ASSERT(newlen >= minlen);
30203 DUK_ASSERT(newlen > 0U);
30204
30205 DUK_DD(DUK_DDPRINT("cbor encode buffer resized to %ld", (long) newlen));
30206
30207 p_new = (duk_uint8_t *) duk_resize_buffer(enc_ctx->thr, enc_ctx->idx_buf, newlen);
30208 DUK_ASSERT(p_new != NULL);
30209 old_data_len = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf);
30210 enc_ctx->buf = p_new;
30211 enc_ctx->buf_end = p_new + newlen;
30212 enc_ctx->ptr = p_new + old_data_len;
30213 enc_ctx->len = newlen;
30214}
30215
30216DUK_LOCAL DUK_INLINE void duk__cbor_encode_ensure(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
30217 if (DUK_LIKELY((duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr) >= len)) {
30218 return;
30219 }
30220 duk__cbor_encode_ensure_slowpath(enc_ctx, len);
30221}
30222
30223DUK_LOCAL duk_size_t duk__cbor_get_reserve(duk_cbor_encode_context *enc_ctx) {
30224 DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf);
30225 DUK_ASSERT(enc_ctx->ptr <= enc_ctx->buf_end);
30226 return (duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr);
30227}
30228
30229DUK_LOCAL void duk__cbor_encode_uint32(duk_cbor_encode_context *enc_ctx, duk_uint32_t u, duk_uint8_t base) {
30230 duk_uint8_t *p;
30231
30232 /* Caller must ensure space. */
30233 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 4);
30234
30235 p = enc_ctx->ptr;
30236 if (DUK_LIKELY(u <= 23U)) {
30237 *p++ = (duk_uint8_t) (base + (duk_uint8_t) u);
30238 } else if (u <= 0xffUL) {
30239 *p++ = base + 0x18U;
30240 *p++ = (duk_uint8_t) u;
30241 } else if (u <= 0xffffUL) {
30242 *p++ = base + 0x19U;
30243 DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) u);
30244 } else {
30245 *p++ = base + 0x1aU;
30246 DUK_RAW_WRITEINC_U32_BE(p, u);
30247 }
30248 enc_ctx->ptr = p;
30249}
30250
30251#if defined(DUK_CBOR_DOUBLE_AS_IS)
30252DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) {
30253 duk_uint8_t *p;
30254
30255 /* Caller must ensure space. */
30256 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30257
30258 p = enc_ctx->ptr;
30259 *p++ = 0xfbU;
30260 DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
30261 p += 8;
30262 enc_ctx->ptr = p;
30263}
30264#else /* DUK_CBOR_DOUBLE_AS_IS */
30265DUK_LOCAL void duk__cbor_encode_double_fp(duk_cbor_encode_context *enc_ctx, double d) {
30266 duk_double_union u;
30267 duk_uint16_t u16;
30268 duk_int16_t expt;
30269 duk_uint8_t *p;
30270
30271 DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO);
30272
30273 /* Caller must ensure space. */
30274 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30275
30276 /* Organize into little endian (no-op if platform is little endian). */
30277 u.d = d;
30278 duk_dblunion_host_to_little(&u);
30279
30280 /* Check if 'd' can represented as a normal half-float.
30281 * Denormal half-floats could also be used, but that check
30282 * isn't done now (denormal half-floats are decoded of course).
30283 * So just check exponent range and that at most 10 significant
30284 * bits (excluding implicit leading 1) are used in 'd'.
30285 */
30286 u16 = (((duk_uint16_t) u.uc[7]) << 8) | ((duk_uint16_t) u.uc[6]);
30287 expt = (duk_int16_t) ((u16 & 0x7ff0U) >> 4) - 1023;
30288
30289 if (expt >= -14 && expt <= 15) {
30290 /* Half-float normal exponents (excl. denormals).
30291 *
30292 * 7 6 5 4 3 2 1 0 (LE index)
30293 * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
30294 * half: seeeee mmmm mmmmmm00 00000000 00000000 00000000 00000000 00000000
30295 */
30296 duk_bool_t use_half_float;
30297
30298 use_half_float =
30299 (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && u.uc[3] == 0 &&
30300 u.uc[4] == 0 && (u.uc[5] & 0x03U) == 0);
30301
30302 if (use_half_float) {
30303 duk_uint32_t t;
30304
30305 expt += 15;
30306 t = (duk_uint32_t) (u.uc[7] & 0x80U) << 8;
30307 t += (duk_uint32_t) expt << 10;
30308 t += ((duk_uint32_t) u.uc[6] & 0x0fU) << 6;
30309 t += ((duk_uint32_t) u.uc[5]) >> 2;
30310
30311 /* seeeeemm mmmmmmmm */
30312 p = enc_ctx->ptr;
30313 *p++ = 0xf9U;
30314 DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) t);
30315 enc_ctx->ptr = p;
30316 return;
30317 }
30318 }
30319
30320 /* Same check for plain float. Also no denormal support here. */
30321 if (expt >= -126 && expt <= 127) {
30322 /* Float normal exponents (excl. denormals).
30323 *
30324 * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
30325 * float: seeee eeeemmmm mmmmmmmm mmmmmmmm mmm00000 00000000 00000000 00000000
30326 */
30327 duk_bool_t use_float;
30328 duk_float_t d_float;
30329
30330 /* We could do this explicit mantissa check, but doing
30331 * a double-float-double cast is fine because we've
30332 * already verified that the exponent is in range so
30333 * that the narrower cast is not undefined behavior.
30334 */
30335#if 0
30336 use_float =
30337 (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && (u.uc[3] & 0xe0U) == 0);
30338#endif
30339 d_float = (duk_float_t) d;
30340 use_float = duk_double_equals((duk_double_t) d_float, d);
30341 if (use_float) {
30342 p = enc_ctx->ptr;
30343 *p++ = 0xfaU;
30344 DUK_RAW_WRITEINC_FLOAT_BE(p, d_float);
30345 enc_ctx->ptr = p;
30346 return;
30347 }
30348 }
30349
30350 /* Special handling for NaN and Inf which we want to encode as
30351 * half-floats. They share the same (maximum) exponent.
30352 */
30353 if (expt == 1024) {
30354 DUK_ASSERT(DUK_ISNAN(d) || DUK_ISINF(d));
30355 p = enc_ctx->ptr;
30356 *p++ = 0xf9U;
30357 if (DUK_ISNAN(d)) {
30358 /* Shortest NaN encoding is using a half-float. Lose the
30359 * exact NaN bits in the process. IEEE double would be
30360 * 7ff8 0000 0000 0000, i.e. a quiet NaN in most architectures
30361 * (https://en.wikipedia.org/wiki/NaN#Encoding). The
30362 * equivalent half float is 7e00.
30363 */
30364 *p++ = 0x7eU;
30365 } else {
30366 /* Shortest +/- Infinity encoding is using a half-float. */
30367 if (DUK_SIGNBIT(d)) {
30368 *p++ = 0xfcU;
30369 } else {
30370 *p++ = 0x7cU;
30371 }
30372 }
30373 *p++ = 0x00U;
30374 enc_ctx->ptr = p;
30375 return;
30376 }
30377
30378 /* Cannot use half-float or float, encode as full IEEE double. */
30379 p = enc_ctx->ptr;
30380 *p++ = 0xfbU;
30381 DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
30382 enc_ctx->ptr = p;
30383}
30384
30385DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) {
30386 duk_uint8_t *p;
30387 double d_floor;
30388
30389 /* Integers and floating point values of all types are conceptually
30390 * equivalent in CBOR. Try to always choose the shortest encoding
30391 * which is not always immediately obvious. For example, NaN and Inf
30392 * can be most compactly represented as a half-float (assuming NaN
30393 * bits are not preserved), and 0x1'0000'0000 as a single precision
30394 * float. Shortest forms in preference order (prefer integer over
30395 * float when equal length):
30396 *
30397 * uint 1 byte [0,23] (not -0)
30398 * sint 1 byte [-24,-1]
30399 * uint+1 2 bytes [24,255]
30400 * sint+1 2 bytes [-256,-25]
30401 * uint+2 3 bytes [256,65535]
30402 * sint+2 3 bytes [-65536,-257]
30403 * half-float 3 bytes -0, NaN, +/- Infinity, range [-65504,65504]
30404 * uint+4 5 bytes [65536,4294967295]
30405 * sint+4 5 bytes [-4294967296,-258]
30406 * float 5 bytes range [-(1 - 2^(-24)) * 2^128, (1 - 2^(-24)) * 2^128]
30407 * uint+8 9 bytes [4294967296,18446744073709551615]
30408 * sint+8 9 bytes [-18446744073709551616,-4294967297]
30409 * double 9 bytes
30410 *
30411 * For whole numbers (compatible with integers):
30412 * - 1-byte or 2-byte uint/sint representation is preferred for
30413 * [-256,255].
30414 * - 3-byte uint/sint is preferred for [-65536,65535]. Half floats
30415 * are never preferred because they have the same length.
30416 * - 5-byte uint/sint is preferred for [-4294967296,4294967295].
30417 * Single precision floats are never preferred, and half-floats
30418 * don't reach above the 3-byte uint/sint range so they're never
30419 * preferred.
30420 * - So, for all integers up to signed/unsigned 32-bit range the
30421 * preferred encoding is always an integer uint/sint.
30422 * - For integers above 32 bits the situation is more complicated.
30423 * Half-floats are never useful for them because of their limited
30424 * range, but IEEE single precision floats (5 bytes encoded) can
30425 * represent some integers between the 32-bit and 64-bit ranges
30426 * which require 9 bytes as a uint/sint.
30427 *
30428 * For floating point values not compatible with integers, the
30429 * preferred encoding is quite clear:
30430 * - For +Inf/-Inf use half-float.
30431 * - For NaN use a half-float, assuming NaN bits ("payload") is
30432 * not worth preserving. Duktape doesn't in general guarantee
30433 * preservation of the NaN payload so using a half-float seems
30434 * consistent with that.
30435 * - For remaining values, prefer the shortest form which doesn't
30436 * lose any precision. For normal half-floats and single precision
30437 * floats this is simple: just check exponent and mantissa bits
30438 * using a fixed mask. For denormal half-floats and single
30439 * precision floats the check is a bit more complicated: a normal
30440 * IEEE double can sometimes be represented as a denormal
30441 * half-float or single precision float.
30442 *
30443 * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#IEEE_754_half-precision_binary_floating-point_format:_binary16
30444 */
30445
30446 /* Caller must ensure space. */
30447 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30448
30449 /* Most important path is integers. The floor() test will be true
30450 * for Inf too (but not NaN).
30451 */
30452 d_floor = DUK_FLOOR(d); /* identity if d is +/- 0.0, NaN, or +/- Infinity */
30453 if (DUK_LIKELY(duk_double_equals(d_floor, d) != 0)) {
30454 DUK_ASSERT(!DUK_ISNAN(d)); /* NaN == NaN compares false. */
30455 if (DUK_SIGNBIT(d)) {
30456 if (d >= -4294967296.0) {
30457 d = -1.0 - d;
30458 if (d >= 0.0) {
30459 DUK_ASSERT(d >= 0.0);
30460 duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x20U);
30461 return;
30462 }
30463
30464 /* Input was negative zero, d == -1.0 < 0.0.
30465 * Shortest -0 is using half-float.
30466 */
30467 p = enc_ctx->ptr;
30468 *p++ = 0xf9U;
30469 *p++ = 0x80U;
30470 *p++ = 0x00U;
30471 enc_ctx->ptr = p;
30472 return;
30473 }
30474 } else {
30475 if (d <= 4294967295.0) {
30476 /* Positive zero needs no special handling. */
30477 DUK_ASSERT(d >= 0.0);
30478 duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x00U);
30479 return;
30480 }
30481 }
30482 }
30483
30484 /* 64-bit integers are not supported at present. So
30485 * we also don't need to deal with choosing between a
30486 * 64-bit uint/sint representation vs. IEEE double or
30487 * float.
30488 */
30489
30490 DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO);
30491 duk__cbor_encode_double_fp(enc_ctx, d);
30492}
30493#endif /* DUK_CBOR_DOUBLE_AS_IS */
30494
30495DUK_LOCAL void duk__cbor_encode_string_top(duk_cbor_encode_context *enc_ctx) {
30496 const duk_uint8_t *str;
30497 duk_size_t len;
30498 duk_uint8_t *p;
30499
30500 /* CBOR differentiates between UTF-8 text strings and byte strings.
30501 * Text strings MUST be valid UTF-8, so not all Duktape strings can
30502 * be encoded as valid CBOR text strings. Possible behaviors:
30503 *
30504 * 1. Use text string when input is valid UTF-8, otherwise use
30505 * byte string (maybe tagged to indicate it was an extended
30506 * UTF-8 string).
30507 * 2. Always use text strings, but sanitize input string so that
30508 * invalid UTF-8 is replaced with U+FFFD for example. Combine
30509 * surrogates whenever possible.
30510 * 3. Always use byte strings. This is simple and produces valid
30511 * CBOR, but isn't ideal for interoperability.
30512 * 4. Always use text strings, even for invalid UTF-8 such as
30513 * codepoints in the surrogate pair range. This is simple but
30514 * produces technically invalid CBOR for non-UTF-8 strings which
30515 * may affect interoperability.
30516 *
30517 * Current default is 1; can be changed with defines.
30518 */
30519
30520 /* Caller must ensure space. */
30521 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30522
30523 str = (const duk_uint8_t *) duk_require_lstring(enc_ctx->thr, -1, &len);
30524 if (duk_is_symbol(enc_ctx->thr, -1)) {
30525 /* Symbols, encode as an empty table for now. This matches
30526 * the behavior of cbor-js.
30527 *
30528 * XXX: Maybe encode String() coercion with a tag?
30529 * XXX: Option to keep enough information to recover
30530 * Symbols when decoding (this is not always desirable).
30531 */
30532 p = enc_ctx->ptr;
30533 *p++ = 0xa0U;
30534 enc_ctx->ptr = p;
30535 return;
30536 }
30537
30538 duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
30539#if defined(DUK_CBOR_TEXT_STRINGS)
30540 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x60U);
30541#elif defined(DUK_CBOR_BYTE_STRINGS)
30542 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
30543#else
30544 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len,
30545 (DUK_LIKELY(duk_unicode_is_utf8_compatible(str, len) != 0) ? 0x60U : 0x40U));
30546#endif
30547 duk__cbor_encode_ensure(enc_ctx, len);
30548 p = enc_ctx->ptr;
30549 duk_memcpy((void *) p, (const void *) str, len);
30550 p += len;
30551 enc_ctx->ptr = p;
30552}
30553
30554DUK_LOCAL void duk__cbor_encode_object(duk_cbor_encode_context *enc_ctx) {
30555 duk_uint8_t *buf;
30556 duk_size_t len;
30557 duk_uint8_t *p;
30558 duk_size_t i;
30559 duk_size_t off_ib;
30560 duk_uint32_t count;
30561
30562 /* Caller must ensure space. */
30563 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30564
30565 duk__cbor_encode_objarr_entry(enc_ctx);
30566
30567 /* XXX: Support for specific built-ins like Date and RegExp. */
30568 if (duk_is_array(enc_ctx->thr, -1)) {
30569 /* Shortest encoding for arrays >= 256 in length is actually
30570 * the indefinite length one (3 or more bytes vs. 2 bytes).
30571 * We still use the definite length version because it is
30572 * more decoding friendly.
30573 */
30574 len = duk_get_length(enc_ctx->thr, -1);
30575 duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
30576 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x80U);
30577 for (i = 0; i < len; i++) {
30578 duk_get_prop_index(enc_ctx->thr, -1, (duk_uarridx_t) i);
30579 duk__cbor_encode_value(enc_ctx);
30580 }
30581 } else if (duk_is_buffer_data(enc_ctx->thr, -1)) {
30582 /* XXX: Tag buffer data?
30583 * XXX: Encode typed arrays as integer arrays rather
30584 * than buffer data as is?
30585 */
30586 buf = (duk_uint8_t *) duk_require_buffer_data(enc_ctx->thr, -1, &len);
30587 duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
30588 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
30589 duk__cbor_encode_ensure(enc_ctx, len);
30590 p = enc_ctx->ptr;
30591 duk_memcpy_unsafe((void *) p, (const void *) buf, len);
30592 p += len;
30593 enc_ctx->ptr = p;
30594 } else {
30595 /* We don't know the number of properties in advance
30596 * but would still like to encode at least small
30597 * objects without indefinite length. Emit an
30598 * indefinite length byte initially, and if the final
30599 * property count is small enough to also fit in one
30600 * byte, backpatch it later. Otherwise keep the
30601 * indefinite length. This works well up to 23
30602 * properties which is practical and good enough.
30603 */
30604 off_ib = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf); /* XXX: get_offset? */
30605 count = 0U;
30606 p = enc_ctx->ptr;
30607 *p++ = 0xa0U + 0x1fU; /* indefinite length */
30608 enc_ctx->ptr = p;
30609 duk_enum(enc_ctx->thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);
30610 while (duk_next(enc_ctx->thr, -1, 1 /*get_value*/)) {
30611 duk_insert(enc_ctx->thr, -2); /* [ ... key value ] -> [ ... value key ] */
30612 duk__cbor_encode_value(enc_ctx);
30613 duk__cbor_encode_value(enc_ctx);
30614 count++;
30615 if (count == 0U) {
30616 duk__cbor_encode_error(enc_ctx);
30617 }
30618 }
30619 duk_pop(enc_ctx->thr);
30620 if (count <= 0x17U) {
30621 DUK_ASSERT(off_ib < enc_ctx->len);
30622 enc_ctx->buf[off_ib] = 0xa0U + (duk_uint8_t) count;
30623 } else {
30624 duk__cbor_encode_ensure(enc_ctx, 1);
30625 p = enc_ctx->ptr;
30626 *p++ = 0xffU; /* break */
30627 enc_ctx->ptr = p;
30628 }
30629 }
30630
30631 duk__cbor_encode_objarr_exit(enc_ctx);
30632}
30633
30634DUK_LOCAL void duk__cbor_encode_buffer(duk_cbor_encode_context *enc_ctx) {
30635 duk_uint8_t *buf;
30636 duk_size_t len;
30637 duk_uint8_t *p;
30638
30639 /* Caller must ensure space. */
30640 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30641
30642 /* Tag buffer data? */
30643 buf = (duk_uint8_t *) duk_require_buffer(enc_ctx->thr, -1, &len);
30644 duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
30645 duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
30646 duk__cbor_encode_ensure(enc_ctx, len);
30647 p = enc_ctx->ptr;
30648 duk_memcpy_unsafe((void *) p, (const void *) buf, len);
30649 p += len;
30650 enc_ctx->ptr = p;
30651}
30652
30653DUK_LOCAL void duk__cbor_encode_pointer(duk_cbor_encode_context *enc_ctx) {
30654 /* Pointers (void *) are challenging to encode. They can't
30655 * be relied to be even 64-bit integer compatible (there are
30656 * pointer models larger than that), nor can floats encode
30657 * them. They could be encoded as strings (%p format) but
30658 * that's not portable. They could be encoded as direct memory
30659 * representations. Recovering pointers is non-portable in any
30660 * case but it would be nice to be able to detect and recover
30661 * compatible pointers.
30662 *
30663 * For now, encode as "(%p)" string, matching JX. There doesn't
30664 * seem to be an appropriate tag, so pointers don't currently
30665 * survive a CBOR encode/decode roundtrip intact.
30666 */
30667 const char *ptr;
30668
30669 ptr = duk_to_string(enc_ctx->thr, -1);
30670 DUK_ASSERT(ptr != NULL);
30671 duk_push_sprintf(enc_ctx->thr, "(%s)", ptr);
30672 duk_remove(enc_ctx->thr, -2);
30673 duk__cbor_encode_string_top(enc_ctx);
30674}
30675
30676DUK_LOCAL void duk__cbor_encode_lightfunc(duk_cbor_encode_context *enc_ctx) {
30677 duk_uint8_t *p;
30678
30679 /* Caller must ensure space. */
30680 DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
30681
30682 /* For now encode as an empty object. */
30683 p = enc_ctx->ptr;
30684 *p++ = 0xa0U;
30685 enc_ctx->ptr = p;
30686}
30687
30688DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx) {
30689 duk_uint8_t *p;
30690
30691 /* Encode/decode cycle currently loses some type information.
30692 * This can be improved by registering custom tags with IANA.
30693 */
30694
30695 /* Reserve space for up to 64-bit types (1 initial byte + 8
30696 * followup bytes). This allows encoding of integers, floats,
30697 * string/buffer length fields, etc without separate checks
30698 * in each code path.
30699 */
30700 duk__cbor_encode_ensure(enc_ctx, 1 + 8);
30701
30702 switch (duk_get_type(enc_ctx->thr, -1)) {
30703 case DUK_TYPE_UNDEFINED: {
30704 p = enc_ctx->ptr;
30705 *p++ = 0xf7;
30706 enc_ctx->ptr = p;
30707 break;
30708 }
30709 case DUK_TYPE_NULL: {
30710 p = enc_ctx->ptr;
30711 *p++ = 0xf6;
30712 enc_ctx->ptr = p;
30713 break;
30714 }
30715 case DUK_TYPE_BOOLEAN: {
30716 duk_uint8_t u8 = duk_get_boolean(enc_ctx->thr, -1) ? 0xf5U : 0xf4U;
30717 p = enc_ctx->ptr;
30718 *p++ = u8;
30719 enc_ctx->ptr = p;
30720 break;
30721 }
30722 case DUK_TYPE_NUMBER: {
30723 duk__cbor_encode_double(enc_ctx, duk_get_number(enc_ctx->thr, -1));
30724 break;
30725 }
30726 case DUK_TYPE_STRING: {
30727 duk__cbor_encode_string_top(enc_ctx);
30728 break;
30729 }
30730 case DUK_TYPE_OBJECT: {
30731 duk__cbor_encode_object(enc_ctx);
30732 break;
30733 }
30734 case DUK_TYPE_BUFFER: {
30735 duk__cbor_encode_buffer(enc_ctx);
30736 break;
30737 }
30738 case DUK_TYPE_POINTER: {
30739 duk__cbor_encode_pointer(enc_ctx);
30740 break;
30741 }
30742 case DUK_TYPE_LIGHTFUNC: {
30743 duk__cbor_encode_lightfunc(enc_ctx);
30744 break;
30745 }
30746 case DUK_TYPE_NONE:
30747 default:
30748 goto fail;
30749 }
30750
30751 duk_pop(enc_ctx->thr);
30752 return;
30753
30754 fail:
30755 duk__cbor_encode_error(enc_ctx);
30756}
30757
30758/*
30759 * Decoding
30760 */
30761
30762DUK_LOCAL void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) {
30763 (void) duk_type_error(dec_ctx->thr, "cbor decode error");
30764}
30765
30766DUK_LOCAL void duk__cbor_decode_req_stack(duk_cbor_decode_context *dec_ctx) {
30767 duk_require_stack(dec_ctx->thr, 4);
30768}
30769
30770DUK_LOCAL void duk__cbor_decode_objarr_entry(duk_cbor_decode_context *dec_ctx) {
30771 duk_hthread *thr = dec_ctx->thr;
30772
30773 /* Native stack check in object/array recursion. */
30774 duk_native_stack_check(thr);
30775
30776 duk__cbor_decode_req_stack(dec_ctx);
30777
30778 DUK_ASSERT(dec_ctx->recursion_depth <= dec_ctx->recursion_limit);
30779 if (dec_ctx->recursion_depth >= dec_ctx->recursion_limit) {
30780 DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT);
30781 DUK_WO_NORETURN(return;);
30782 }
30783 dec_ctx->recursion_depth++;
30784}
30785
30786DUK_LOCAL void duk__cbor_decode_objarr_exit(duk_cbor_decode_context *dec_ctx) {
30787 DUK_ASSERT(dec_ctx->recursion_depth > 0);
30788 dec_ctx->recursion_depth--;
30789}
30790
30791DUK_LOCAL duk_uint8_t duk__cbor_decode_readbyte(duk_cbor_decode_context *dec_ctx) {
30792 DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
30793 if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 1U)) {
30794 duk__cbor_decode_error(dec_ctx);
30795 }
30796 return dec_ctx->buf[dec_ctx->off++];
30797}
30798
30799DUK_LOCAL duk_uint16_t duk__cbor_decode_read_u16(duk_cbor_decode_context *dec_ctx) {
30800 duk_uint16_t res;
30801
30802 DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
30803 if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 2U)) {
30804 duk__cbor_decode_error(dec_ctx);
30805 }
30806 res = DUK_RAW_READ_U16_BE(dec_ctx->buf + dec_ctx->off);
30807 dec_ctx->off += 2;
30808 return res;
30809}
30810
30811DUK_LOCAL duk_uint32_t duk__cbor_decode_read_u32(duk_cbor_decode_context *dec_ctx) {
30812 duk_uint32_t res;
30813
30814 DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
30815 if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 4U)) {
30816 duk__cbor_decode_error(dec_ctx);
30817 }
30818 res = DUK_RAW_READ_U32_BE(dec_ctx->buf + dec_ctx->off);
30819 dec_ctx->off += 4;
30820 return res;
30821}
30822
30823DUK_LOCAL duk_uint8_t duk__cbor_decode_peekbyte(duk_cbor_decode_context *dec_ctx) {
30824 if (DUK_UNLIKELY(dec_ctx->off >= dec_ctx->len)) {
30825 duk__cbor_decode_error(dec_ctx);
30826 }
30827 return dec_ctx->buf[dec_ctx->off];
30828}
30829
30830DUK_LOCAL void duk__cbor_decode_rewind(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
30831 DUK_ASSERT(len <= dec_ctx->off); /* Caller must ensure. */
30832 dec_ctx->off -= len;
30833}
30834
30835#if 0
30836DUK_LOCAL void duk__cbor_decode_ensure(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
30837 if (dec_ctx->off + len > dec_ctx->len) {
30838 duk__cbor_decode_error(dec_ctx);
30839 }
30840}
30841#endif
30842
30843DUK_LOCAL const duk_uint8_t *duk__cbor_decode_consume(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
30844 DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
30845 if (DUK_LIKELY(dec_ctx->len - dec_ctx->off >= len)) {
30846 const duk_uint8_t *res = dec_ctx->buf + dec_ctx->off;
30847 dec_ctx->off += len;
30848 return res;
30849 }
30850
30851 duk__cbor_decode_error(dec_ctx); /* Not enough input. */
30852 return NULL;
30853}
30854
30855DUK_LOCAL int duk__cbor_decode_checkbreak(duk_cbor_decode_context *dec_ctx) {
30856 if (duk__cbor_decode_peekbyte(dec_ctx) == 0xffU) {
30857 DUK_ASSERT(dec_ctx->off < dec_ctx->len);
30858 dec_ctx->off++;
30859#if 0
30860 (void) duk__cbor_decode_readbyte(dec_ctx);
30861#endif
30862 return 1;
30863 }
30864 return 0;
30865}
30866
30867DUK_LOCAL void duk__cbor_decode_push_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_bool_t negative) {
30868 duk_uint8_t ai;
30869 duk_uint32_t t, t1, t2;
30870#if 0
30871 duk_uint64_t t3;
30872#endif
30873 duk_double_t d1, d2;
30874 duk_double_t d;
30875
30876 ai = ib & 0x1fU;
30877 if (ai <= 0x17U) {
30878 t = ai;
30879 goto shared_exit;
30880 }
30881
30882 switch (ai) {
30883 case 0x18U: /* 1 byte */
30884 t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx);
30885 goto shared_exit;
30886 case 0x19U: /* 2 byte */
30887 t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx);
30888 goto shared_exit;
30889 case 0x1aU: /* 4 byte */
30890 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
30891 goto shared_exit;
30892 case 0x1bU: /* 8 byte */
30893 /* For uint64 it's important to handle the -1.0 part before
30894 * casting to double: otherwise the adjustment might be lost
30895 * in the cast. Uses: -1.0 - d <=> -(d + 1.0).
30896 */
30897 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
30898 t2 = t;
30899 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
30900 t1 = t;
30901#if 0
30902 t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1;
30903 if (negative) {
30904 if (t3 == DUK_UINT64_MAX) {
30905 /* -(0xffff'ffff'ffff'ffffULL + 1) =
30906 * -0x1'0000'0000'0000'0000
30907 *
30908 * >>> -0x10000000000000000
30909 * -18446744073709551616L
30910 */
30911 return -18446744073709551616.0;
30912 } else {
30913 return -((duk_double_t) (t3 + DUK_U64_CONSTANT(1)));
30914 }
30915 } else {
30916 return (duk_double_t) t3; /* XXX: cast helper */
30917 }
30918#endif
30919#if 0
30920 t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1;
30921 if (negative) {
30922 /* Simpler version: take advantage of the fact that
30923 * 0xffff'ffff'ffff'ffff and 0x1'0000'0000'0000'0000
30924 * both round to 0x1'0000'0000'0000'0000:
30925 * > (0xffffffffffffffff).toString(16)
30926 * '10000000000000000'
30927 * > (0x10000000000000000).toString(16)
30928 * '10000000000000000'
30929 *
30930 * For the DUK_UINT64_MAX case we just skip the +1
30931 * increment to avoid wrapping; the result still
30932 * comes out right for an IEEE double cast.
30933 */
30934 if (t3 != DUK_UINT64_MAX) {
30935 t3++;
30936 }
30937 return -((duk_double_t) t3);
30938 } else {
30939 return (duk_double_t) t3; /* XXX: cast helper */
30940 }
30941#endif
30942#if 1
30943 /* Use two double parts, avoids dependency on 64-bit type.
30944 * Avoid precision loss carefully, especially when dealing
30945 * with the required +1 for negative values.
30946 *
30947 * No fastint check for this path at present.
30948 */
30949 d1 = (duk_double_t) t1; /* XXX: cast helpers */
30950 d2 = (duk_double_t) t2 * 4294967296.0;
30951 if (negative) {
30952 d1 += 1.0;
30953 }
30954 d = d2 + d1;
30955 if (negative) {
30956 d = -d;
30957 }
30958#endif
30959 /* XXX: a push and check for fastint API would be nice */
30960 duk_push_number(dec_ctx->thr, d);
30961 return;
30962 }
30963
30964 duk__cbor_decode_error(dec_ctx);
30965 return;
30966
30967 shared_exit:
30968 if (negative) {
30969 /* XXX: a push and check for fastint API would be nice */
30970 if ((duk_uint_t) t <= (duk_uint_t) -(DUK_INT_MIN + 1)) {
30971 duk_push_int(dec_ctx->thr, -1 - ((duk_int_t) t));
30972 } else {
30973 duk_push_number(dec_ctx->thr, -1.0 - (duk_double_t) t);
30974 }
30975 } else {
30976 duk_push_uint(dec_ctx->thr, (duk_uint_t) t);
30977 }
30978}
30979
30980DUK_LOCAL void duk__cbor_decode_skip_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) {
30981 const duk_int8_t skips[32] = {
30982 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30983 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, -1, -1, -1, -1
30984 };
30985 duk_uint8_t ai;
30986 duk_int8_t skip;
30987
30988 ai = ib & 0x1fU;
30989 skip = skips[ai];
30990 if (DUK_UNLIKELY(skip < 0)) {
30991 duk__cbor_decode_error(dec_ctx);
30992 }
30993 duk__cbor_decode_consume(dec_ctx, (duk_size_t) skip);
30994 return;
30995}
30996
30997DUK_LOCAL duk_uint32_t duk__cbor_decode_aival_uint32(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) {
30998 duk_uint8_t ai;
30999 duk_uint32_t t;
31000
31001 ai = ib & 0x1fU;
31002 if (ai <= 0x17U) {
31003 return (duk_uint32_t) ai;
31004 }
31005
31006 switch (ai) {
31007 case 0x18U: /* 1 byte */
31008 t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx);
31009 return t;
31010 case 0x19U: /* 2 byte */
31011 t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx);
31012 return t;
31013 case 0x1aU: /* 4 byte */
31014 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
31015 return t;
31016 case 0x1bU: /* 8 byte */
31017 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
31018 if (t != 0U) {
31019 break;
31020 }
31021 t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
31022 return t;
31023 }
31024
31025 duk__cbor_decode_error(dec_ctx);
31026 return 0U;
31027}
31028
31029DUK_LOCAL void duk__cbor_decode_buffer(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) {
31030 duk_uint32_t len;
31031 duk_uint8_t *buf;
31032 const duk_uint8_t *inp;
31033 duk_uint8_t ib;
31034
31035 ib = duk__cbor_decode_readbyte(dec_ctx);
31036 if ((ib & 0xe0U) != expected_base) {
31037 duk__cbor_decode_error(dec_ctx);
31038 }
31039 /* Indefinite format is rejected by the following on purpose. */
31040 len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
31041 inp = duk__cbor_decode_consume(dec_ctx, len);
31042 /* XXX: duk_push_fixed_buffer_with_data() would be a nice API addition. */
31043 buf = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, (duk_size_t) len);
31044 duk_memcpy((void *) buf, (const void *) inp, (size_t) len);
31045}
31046
31047DUK_LOCAL void duk__cbor_decode_join_buffers(duk_cbor_decode_context *dec_ctx, duk_idx_t count) {
31048 duk_size_t total_size = 0;
31049 duk_idx_t top = duk_get_top(dec_ctx->thr);
31050 duk_idx_t base = top - count; /* count is >= 1 */
31051 duk_idx_t idx;
31052 duk_uint8_t *p = NULL;
31053
31054 DUK_ASSERT(count >= 1);
31055 DUK_ASSERT(top >= count);
31056
31057 for (;;) {
31058 /* First round: compute total size.
31059 * Second round: copy into place.
31060 */
31061 for (idx = base; idx < top; idx++) {
31062 duk_uint8_t *buf_data;
31063 duk_size_t buf_size;
31064
31065 buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, idx, &buf_size);
31066 if (p != NULL) {
31067 duk_memcpy_unsafe((void *) p, (const void *) buf_data, buf_size);
31068 p += buf_size;
31069 } else {
31070 total_size += buf_size;
31071 if (DUK_UNLIKELY(total_size < buf_size)) { /* Wrap check. */
31072 duk__cbor_decode_error(dec_ctx);
31073 }
31074 }
31075 }
31076
31077 if (p != NULL) {
31078 break;
31079 } else {
31080 p = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, total_size);
31081 DUK_ASSERT(p != NULL);
31082 }
31083 }
31084
31085 duk_replace(dec_ctx->thr, base);
31086 duk_pop_n(dec_ctx->thr, count - 1);
31087}
31088
31089DUK_LOCAL void duk__cbor_decode_and_join_strbuf(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) {
31090 duk_idx_t count = 0;
31091 for (;;) {
31092 if (duk__cbor_decode_checkbreak(dec_ctx)) {
31093 break;
31094 }
31095 duk_require_stack(dec_ctx->thr, 1);
31096 duk__cbor_decode_buffer(dec_ctx, expected_base);
31097 count++;
31098 if (DUK_UNLIKELY(count <= 0)) { /* Wrap check. */
31099 duk__cbor_decode_error(dec_ctx);
31100 }
31101 }
31102 if (count == 0) {
31103 (void) duk_push_fixed_buffer(dec_ctx->thr, 0);
31104 } else if (count > 1) {
31105 duk__cbor_decode_join_buffers(dec_ctx, count);
31106 }
31107}
31108
31109DUK_LOCAL duk_double_t duk__cbor_decode_half_float(duk_cbor_decode_context *dec_ctx) {
31110 duk_double_union u;
31111 const duk_uint8_t *inp;
31112 duk_int_t expt;
31113 duk_uint_t u16;
31114 duk_uint_t tmp;
31115 duk_double_t res;
31116
31117 inp = duk__cbor_decode_consume(dec_ctx, 2);
31118 u16 = ((duk_uint_t) inp[0] << 8) + (duk_uint_t) inp[1];
31119 expt = (duk_int_t) ((u16 >> 10) & 0x1fU) - 15;
31120
31121 /* Reconstruct IEEE double into little endian order first, then convert
31122 * to host order.
31123 */
31124
31125 duk_memzero((void *) &u, sizeof(u));
31126
31127 if (expt == -15) {
31128 /* Zero or denormal; but note that half float
31129 * denormals become double normals.
31130 */
31131 if ((u16 & 0x03ffU) == 0) {
31132 u.uc[7] = inp[0] & 0x80U;
31133 } else {
31134 /* Create denormal by first creating a double that
31135 * contains the denormal bits and a leading implicit
31136 * 1-bit. Then subtract away the implicit 1-bit.
31137 *
31138 * 0.mmmmmmmmmm * 2^-14
31139 * 1.mmmmmmmmmm 0.... * 2^-14
31140 * -1.0000000000 0.... * 2^-14
31141 *
31142 * Double exponent: -14 + 1023 = 0x3f1
31143 */
31144 u.uc[7] = 0x3fU;
31145 u.uc[6] = 0x10U + (duk_uint8_t) ((u16 >> 6) & 0x0fU);
31146 u.uc[5] = (duk_uint8_t) ((u16 << 2) & 0xffU); /* Mask is really 0xfcU */
31147
31148 duk_dblunion_little_to_host(&u);
31149 res = u.d - 0.00006103515625; /* 2^(-14) */
31150 if (u16 & 0x8000U) {
31151 res = -res;
31152 }
31153 return res;
31154 }
31155 } else if (expt == 16) {
31156 /* +/- Inf or NaN. */
31157 if ((u16 & 0x03ffU) == 0) {
31158 u.uc[7] = (inp[0] & 0x80U) + 0x7fU;
31159 u.uc[6] = 0xf0U;
31160 } else {
31161 /* Create a 'quiet NaN' with highest
31162 * bit set (there are some platforms
31163 * where the NaN payload convention is
31164 * the opposite). Keep sign.
31165 */
31166 u.uc[7] = (inp[0] & 0x80U) + 0x7fU;
31167 u.uc[6] = 0xf8U;
31168 }
31169 } else {
31170 /* Normal. */
31171 tmp = (inp[0] & 0x80U) ? 0x80000000UL : 0UL;
31172 tmp += (duk_uint_t) (expt + 1023) << 20;
31173 tmp += (duk_uint_t) (inp[0] & 0x03U) << 18;
31174 tmp += (duk_uint_t) (inp[1] & 0xffU) << 10;
31175 u.uc[7] = (tmp >> 24) & 0xffU;
31176 u.uc[6] = (tmp >> 16) & 0xffU;
31177 u.uc[5] = (tmp >> 8) & 0xffU;
31178 u.uc[4] = (tmp >> 0) & 0xffU;
31179 }
31180
31181 duk_dblunion_little_to_host(&u);
31182 return u.d;
31183}
31184
31185DUK_LOCAL void duk__cbor_decode_string(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
31186 /* If the CBOR string data is not valid UTF-8 it is technically
31187 * invalid CBOR. Possible behaviors at least:
31188 *
31189 * 1. Reject the input, i.e. throw TypeError.
31190 *
31191 * 2. Accept the input, but sanitize non-UTF-8 data into UTF-8
31192 * using U+FFFD replacements. Also it might make sense to
31193 * decode non-BMP codepoints into surrogates for better
31194 * ECMAScript compatibility.
31195 *
31196 * 3. Accept the input as a Duktape string (which are not always
31197 * valid UTF-8), but reject any input that would create a
31198 * Symbol representation.
31199 *
31200 * Current behavior is 3.
31201 */
31202
31203 if (ai == 0x1fU) {
31204 duk_uint8_t *buf_data;
31205 duk_size_t buf_size;
31206
31207 duk__cbor_decode_and_join_strbuf(dec_ctx, 0x60U);
31208 buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, -1, &buf_size);
31209 (void) duk_push_lstring(dec_ctx->thr, (const char *) buf_data, buf_size);
31210 duk_remove(dec_ctx->thr, -2);
31211 } else {
31212 duk_uint32_t len;
31213 const duk_uint8_t *inp;
31214
31215 len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
31216 inp = duk__cbor_decode_consume(dec_ctx, len);
31217 (void) duk_push_lstring(dec_ctx->thr, (const char *) inp, (duk_size_t) len);
31218 }
31219 if (duk_is_symbol(dec_ctx->thr, -1)) {
31220 /* Refuse to create Symbols when decoding. */
31221 duk__cbor_decode_error(dec_ctx);
31222 }
31223
31224 /* XXX: Here a Duktape API call to convert input -> utf-8 with
31225 * replacements would be nice.
31226 */
31227}
31228
31229DUK_LOCAL duk_bool_t duk__cbor_decode_array(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
31230 duk_uint32_t idx, len;
31231
31232 duk__cbor_decode_objarr_entry(dec_ctx);
31233
31234 /* Support arrays up to 0xfffffffeU in length. 0xffffffff is
31235 * used as an indefinite length marker.
31236 */
31237 if (ai == 0x1fU) {
31238 len = 0xffffffffUL;
31239 } else {
31240 len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
31241 if (len == 0xffffffffUL) {
31242 goto failure;
31243 }
31244 }
31245
31246 /* XXX: use bare array? */
31247 duk_push_array(dec_ctx->thr);
31248 for (idx = 0U; ;) {
31249 if (len == 0xffffffffUL && duk__cbor_decode_checkbreak(dec_ctx)) {
31250 break;
31251 }
31252 if (idx == len) {
31253 if (ai == 0x1fU) {
31254 goto failure;
31255 }
31256 break;
31257 }
31258 duk__cbor_decode_value(dec_ctx);
31259 duk_put_prop_index(dec_ctx->thr, -2, (duk_uarridx_t) idx);
31260 idx++;
31261 if (idx == 0U) {
31262 goto failure; /* wrapped */
31263 }
31264 }
31265
31266#if 0
31267 success:
31268#endif
31269 duk__cbor_decode_objarr_exit(dec_ctx);
31270 return 1;
31271
31272 failure:
31273 /* No need to unwind recursion checks, caller will throw. */
31274 return 0;
31275}
31276
31277DUK_LOCAL duk_bool_t duk__cbor_decode_map(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
31278 duk_uint32_t count;
31279
31280 duk__cbor_decode_objarr_entry(dec_ctx);
31281
31282 if (ai == 0x1fU) {
31283 count = 0xffffffffUL;
31284 } else {
31285 count = duk__cbor_decode_aival_uint32(dec_ctx, ib);
31286 if (count == 0xffffffffUL) {
31287 goto failure;
31288 }
31289 }
31290
31291 /* XXX: use bare object? */
31292 duk_push_object(dec_ctx->thr);
31293 for (;;) {
31294 if (count == 0xffffffffUL) {
31295 if (duk__cbor_decode_checkbreak(dec_ctx)) {
31296 break;
31297 }
31298 } else {
31299 if (count == 0UL) {
31300 break;
31301 }
31302 count--;
31303 }
31304
31305 /* Non-string keys are coerced to strings,
31306 * possibly leading to overwriting previous
31307 * keys. Last key of a certain coerced name
31308 * wins. If key is an object, it will coerce
31309 * to '[object Object]' which is consistent
31310 * but potentially misleading. One alternative
31311 * would be to skip non-string keys.
31312 */
31313 duk__cbor_decode_value(dec_ctx);
31314 duk__cbor_decode_value(dec_ctx);
31315 duk_put_prop(dec_ctx->thr, -3);
31316 }
31317
31318#if 0
31319 success:
31320#endif
31321 duk__cbor_decode_objarr_exit(dec_ctx);
31322 return 1;
31323
31324 failure:
31325 /* No need to unwind recursion checks, caller will throw. */
31326 return 0;
31327}
31328
31329DUK_LOCAL duk_double_t duk__cbor_decode_float(duk_cbor_decode_context *dec_ctx) {
31330 duk_float_union u;
31331 const duk_uint8_t *inp;
31332 inp = duk__cbor_decode_consume(dec_ctx, 4);
31333 duk_memcpy((void *) u.uc, (const void *) inp, 4);
31334 duk_fltunion_big_to_host(&u);
31335 return (duk_double_t) u.f;
31336}
31337
31338DUK_LOCAL duk_double_t duk__cbor_decode_double(duk_cbor_decode_context *dec_ctx) {
31339 duk_double_union u;
31340 const duk_uint8_t *inp;
31341 inp = duk__cbor_decode_consume(dec_ctx, 8);
31342 duk_memcpy((void *) u.uc, (const void *) inp, 8);
31343 duk_dblunion_big_to_host(&u);
31344 return u.d;
31345}
31346
31347#if defined(DUK_CBOR_DECODE_FASTPATH)
31348#define DUK__CBOR_AI (ib & 0x1fU)
31349
31350DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) {
31351 duk_uint8_t ib;
31352
31353 /* Any paths potentially recursing back to duk__cbor_decode_value()
31354 * must perform a Duktape value stack growth check. Avoid the check
31355 * here for simple paths like primitive values.
31356 */
31357
31358 reread_initial_byte:
31359 DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld", (long) dec_ctx->off, (long) dec_ctx->len));
31360
31361 ib = duk__cbor_decode_readbyte(dec_ctx);
31362
31363 /* Full initial byte switch, footprint cost over baseline is ~+1kB. */
31364 /* XXX: Force full switch with no range check. */
31365
31366 switch (ib) {
31367 case 0x00U: case 0x01U: case 0x02U: case 0x03U: case 0x04U: case 0x05U: case 0x06U: case 0x07U:
31368 case 0x08U: case 0x09U: case 0x0aU: case 0x0bU: case 0x0cU: case 0x0dU: case 0x0eU: case 0x0fU:
31369 case 0x10U: case 0x11U: case 0x12U: case 0x13U: case 0x14U: case 0x15U: case 0x16U: case 0x17U:
31370 duk_push_uint(dec_ctx->thr, ib);
31371 break;
31372 case 0x18U: case 0x19U: case 0x1aU: case 0x1bU:
31373 duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/);
31374 break;
31375 case 0x1cU: case 0x1dU: case 0x1eU: case 0x1fU:
31376 goto format_error;
31377 case 0x20U: case 0x21U: case 0x22U: case 0x23U: case 0x24U: case 0x25U: case 0x26U: case 0x27U:
31378 case 0x28U: case 0x29U: case 0x2aU: case 0x2bU: case 0x2cU: case 0x2dU: case 0x2eU: case 0x2fU:
31379 case 0x30U: case 0x31U: case 0x32U: case 0x33U: case 0x34U: case 0x35U: case 0x36U: case 0x37U:
31380 duk_push_int(dec_ctx->thr, -((duk_int_t) ((ib - 0x20U) + 1U)));
31381 break;
31382 case 0x38U: case 0x39U: case 0x3aU: case 0x3bU:
31383 duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/);
31384 break;
31385 case 0x3cU: case 0x3dU: case 0x3eU: case 0x3fU:
31386 goto format_error;
31387 case 0x40U: case 0x41U: case 0x42U: case 0x43U: case 0x44U: case 0x45U: case 0x46U: case 0x47U:
31388 case 0x48U: case 0x49U: case 0x4aU: case 0x4bU: case 0x4cU: case 0x4dU: case 0x4eU: case 0x4fU:
31389 case 0x50U: case 0x51U: case 0x52U: case 0x53U: case 0x54U: case 0x55U: case 0x56U: case 0x57U:
31390 /* XXX: Avoid rewind, we know the length already. */
31391 DUK_ASSERT(dec_ctx->off > 0U);
31392 dec_ctx->off--;
31393 duk__cbor_decode_buffer(dec_ctx, 0x40U);
31394 break;
31395 case 0x58U: case 0x59U: case 0x5aU: case 0x5bU:
31396 /* XXX: Avoid rewind, decode length inline. */
31397 DUK_ASSERT(dec_ctx->off > 0U);
31398 dec_ctx->off--;
31399 duk__cbor_decode_buffer(dec_ctx, 0x40U);
31400 break;
31401 case 0x5cU: case 0x5dU: case 0x5eU:
31402 goto format_error;
31403 case 0x5fU:
31404 duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U);
31405 break;
31406 case 0x60U: case 0x61U: case 0x62U: case 0x63U: case 0x64U: case 0x65U: case 0x66U: case 0x67U:
31407 case 0x68U: case 0x69U: case 0x6aU: case 0x6bU: case 0x6cU: case 0x6dU: case 0x6eU: case 0x6fU:
31408 case 0x70U: case 0x71U: case 0x72U: case 0x73U: case 0x74U: case 0x75U: case 0x76U: case 0x77U:
31409 /* XXX: Avoid double decode of length. */
31410 duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
31411 break;
31412 case 0x78U: case 0x79U: case 0x7aU: case 0x7bU:
31413 /* XXX: Avoid double decode of length. */
31414 duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
31415 break;
31416 case 0x7cU: case 0x7dU: case 0x7eU:
31417 goto format_error;
31418 case 0x7fU:
31419 duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
31420 break;
31421 case 0x80U: case 0x81U: case 0x82U: case 0x83U: case 0x84U: case 0x85U: case 0x86U: case 0x87U:
31422 case 0x88U: case 0x89U: case 0x8aU: case 0x8bU: case 0x8cU: case 0x8dU: case 0x8eU: case 0x8fU:
31423 case 0x90U: case 0x91U: case 0x92U: case 0x93U: case 0x94U: case 0x95U: case 0x96U: case 0x97U:
31424 if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31425 goto format_error;
31426 }
31427 break;
31428 case 0x98U: case 0x99U: case 0x9aU: case 0x9bU:
31429 if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31430 goto format_error;
31431 }
31432 break;
31433 case 0x9cU: case 0x9dU: case 0x9eU:
31434 goto format_error;
31435 case 0x9fU:
31436 if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31437 goto format_error;
31438 }
31439 break;
31440 case 0xa0U: case 0xa1U: case 0xa2U: case 0xa3U: case 0xa4U: case 0xa5U: case 0xa6U: case 0xa7U:
31441 case 0xa8U: case 0xa9U: case 0xaaU: case 0xabU: case 0xacU: case 0xadU: case 0xaeU: case 0xafU:
31442 case 0xb0U: case 0xb1U: case 0xb2U: case 0xb3U: case 0xb4U: case 0xb5U: case 0xb6U: case 0xb7U:
31443 if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31444 goto format_error;
31445 }
31446 break;
31447 case 0xb8U: case 0xb9U: case 0xbaU: case 0xbbU:
31448 if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31449 goto format_error;
31450 }
31451 break;
31452 case 0xbcU: case 0xbdU: case 0xbeU:
31453 goto format_error;
31454 case 0xbfU:
31455 if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
31456 goto format_error;
31457 }
31458 break;
31459 case 0xc0U: case 0xc1U: case 0xc2U: case 0xc3U: case 0xc4U: case 0xc5U: case 0xc6U: case 0xc7U:
31460 case 0xc8U: case 0xc9U: case 0xcaU: case 0xcbU: case 0xccU: case 0xcdU: case 0xceU: case 0xcfU:
31461 case 0xd0U: case 0xd1U: case 0xd2U: case 0xd3U: case 0xd4U: case 0xd5U: case 0xd6U: case 0xd7U:
31462 /* Tag 0-23: drop. */
31463 goto reread_initial_byte;
31464 case 0xd8U: case 0xd9U: case 0xdaU: case 0xdbU:
31465 duk__cbor_decode_skip_aival_int(dec_ctx, ib);
31466 goto reread_initial_byte;
31467 case 0xdcU: case 0xddU: case 0xdeU: case 0xdfU:
31468 goto format_error;
31469 case 0xe0U:
31470 goto format_error;
31471 case 0xe1U:
31472 goto format_error;
31473 case 0xe2U:
31474 goto format_error;
31475 case 0xe3U:
31476 goto format_error;
31477 case 0xe4U:
31478 goto format_error;
31479 case 0xe5U:
31480 goto format_error;
31481 case 0xe6U:
31482 goto format_error;
31483 case 0xe7U:
31484 goto format_error;
31485 case 0xe8U:
31486 goto format_error;
31487 case 0xe9U:
31488 goto format_error;
31489 case 0xeaU:
31490 goto format_error;
31491 case 0xebU:
31492 goto format_error;
31493 case 0xecU:
31494 goto format_error;
31495 case 0xedU:
31496 goto format_error;
31497 case 0xeeU:
31498 goto format_error;
31499 case 0xefU:
31500 goto format_error;
31501 case 0xf0U:
31502 goto format_error;
31503 case 0xf1U:
31504 goto format_error;
31505 case 0xf2U:
31506 goto format_error;
31507 case 0xf3U:
31508 goto format_error;
31509 case 0xf4U:
31510 duk_push_false(dec_ctx->thr);
31511 break;
31512 case 0xf5U:
31513 duk_push_true(dec_ctx->thr);
31514 break;
31515 case 0xf6U:
31516 duk_push_null(dec_ctx->thr);
31517 break;
31518 case 0xf7U:
31519 duk_push_undefined(dec_ctx->thr);
31520 break;
31521 case 0xf8U:
31522 /* Simple value 32-255, nothing defined yet, so reject. */
31523 goto format_error;
31524 case 0xf9U: {
31525 duk_double_t d;
31526 d = duk__cbor_decode_half_float(dec_ctx);
31527 duk_push_number(dec_ctx->thr, d);
31528 break;
31529 }
31530 case 0xfaU: {
31531 duk_double_t d;
31532 d = duk__cbor_decode_float(dec_ctx);
31533 duk_push_number(dec_ctx->thr, d);
31534 break;
31535 }
31536 case 0xfbU: {
31537 duk_double_t d;
31538 d = duk__cbor_decode_double(dec_ctx);
31539 duk_push_number(dec_ctx->thr, d);
31540 break;
31541 }
31542 case 0xfcU:
31543 case 0xfdU:
31544 case 0xfeU:
31545 case 0xffU:
31546 goto format_error;
31547 } /* end switch */
31548
31549 return;
31550
31551 format_error:
31552 duk__cbor_decode_error(dec_ctx);
31553}
31554#else /* DUK_CBOR_DECODE_FASTPATH */
31555DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) {
31556 duk_uint8_t ib, mt, ai;
31557
31558 /* Any paths potentially recursing back to duk__cbor_decode_value()
31559 * must perform a Duktape value stack growth check. Avoid the check
31560 * here for simple paths like primitive values.
31561 */
31562
31563 reread_initial_byte:
31564 DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld", (long) dec_ctx->off, (long) dec_ctx->len));
31565
31566 ib = duk__cbor_decode_readbyte(dec_ctx);
31567 mt = ib >> 5U;
31568 ai = ib & 0x1fU;
31569
31570 /* Additional information in [24,27] = [0x18,0x1b] has relatively
31571 * uniform handling for all major types: read 1/2/4/8 additional
31572 * bytes. For major type 7 the 1-byte value is a 'simple type', and
31573 * 2/4/8-byte values are floats. For other major types the 1/2/4/8
31574 * byte values are integers. The lengths are uniform, but the typing
31575 * is not.
31576 */
31577
31578 switch (mt) {
31579 case 0U: { /* unsigned integer */
31580 duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/);
31581 break;
31582 }
31583 case 1U: { /* negative integer */
31584 duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/);
31585 break;
31586 }
31587 case 2U: { /* byte string */
31588 if (ai == 0x1fU) {
31589 duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U);
31590 } else {
31591 duk__cbor_decode_rewind(dec_ctx, 1U);
31592 duk__cbor_decode_buffer(dec_ctx, 0x40U);
31593 }
31594 break;
31595 }
31596 case 3U: { /* text string */
31597 duk__cbor_decode_string(dec_ctx, ib, ai);
31598 break;
31599 }
31600 case 4U: { /* array of data items */
31601 if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, ai) == 0)) {
31602 goto format_error;
31603 }
31604 break;
31605 }
31606 case 5U: { /* map of pairs of data items */
31607 if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, ai) == 0)) {
31608 goto format_error;
31609 }
31610 break;
31611 }
31612 case 6U: { /* semantic tagging */
31613 /* Tags are ignored now, re-read initial byte. A tagged
31614 * value may itself be tagged (an unlimited number of times)
31615 * so keep on peeling away tags.
31616 */
31617 duk__cbor_decode_skip_aival_int(dec_ctx, ib);
31618 goto reread_initial_byte;
31619 }
31620 case 7U: { /* floating point numbers, simple data types, break; other */
31621 switch (ai) {
31622 case 0x14U: {
31623 duk_push_false(dec_ctx->thr);
31624 break;
31625 }
31626 case 0x15U: {
31627 duk_push_true(dec_ctx->thr);
31628 break;
31629 }
31630 case 0x16U: {
31631 duk_push_null(dec_ctx->thr);
31632 break;
31633 }
31634 case 0x17U: {
31635 duk_push_undefined(dec_ctx->thr);
31636 break;
31637 }
31638 case 0x18U: { /* more simple values (1 byte) */
31639 /* Simple value encoded in additional byte (none
31640 * are defined so far). RFC 7049 states that the
31641 * follow-up byte must be 32-255 to minimize
31642 * confusion. So, a non-shortest encoding like
31643 * f815 (= true, shortest encoding f5) must be
31644 * rejected. cbor.me tester rejects f815, but
31645 * e.g. Python CBOR binding decodes it as true.
31646 */
31647 goto format_error;
31648 }
31649 case 0x19U: { /* half-float (2 bytes) */
31650 duk_double_t d;
31651 d = duk__cbor_decode_half_float(dec_ctx);
31652 duk_push_number(dec_ctx->thr, d);
31653 break;
31654 }
31655 case 0x1aU: { /* float (4 bytes) */
31656 duk_double_t d;
31657 d = duk__cbor_decode_float(dec_ctx);
31658 duk_push_number(dec_ctx->thr, d);
31659 break;
31660 }
31661 case 0x1bU: { /* double (8 bytes) */
31662 duk_double_t d;
31663 d = duk__cbor_decode_double(dec_ctx);
31664 duk_push_number(dec_ctx->thr, d);
31665 break;
31666 }
31667 case 0xffU: /* unexpected break */
31668 default: {
31669 goto format_error;
31670 }
31671 } /* end switch */
31672 break;
31673 }
31674 default: {
31675 goto format_error; /* will never actually occur */
31676 }
31677 } /* end switch */
31678
31679 return;
31680
31681 format_error:
31682 duk__cbor_decode_error(dec_ctx);
31683}
31684#endif /* DUK_CBOR_DECODE_FASTPATH */
31685
31686DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
31687 duk_cbor_encode_context enc_ctx;
31688 duk_uint8_t *buf;
31689
31690 DUK_UNREF(encode_flags);
31691
31692 idx = duk_require_normalize_index(thr, idx);
31693
31694 enc_ctx.thr = thr;
31695 enc_ctx.idx_buf = duk_get_top(thr);
31696
31697 enc_ctx.len = 64;
31698 buf = (duk_uint8_t *) duk_push_dynamic_buffer(thr, enc_ctx.len);
31699 enc_ctx.ptr = buf;
31700 enc_ctx.buf = buf;
31701 enc_ctx.buf_end = buf + enc_ctx.len;
31702
31703 enc_ctx.recursion_depth = 0;
31704 enc_ctx.recursion_limit = DUK_USE_CBOR_ENC_RECLIMIT;
31705
31706 duk_dup(thr, idx);
31707 duk__cbor_encode_req_stack(&enc_ctx);
31708 duk__cbor_encode_value(&enc_ctx);
31709 DUK_ASSERT(enc_ctx.recursion_depth == 0);
31710 duk_resize_buffer(enc_ctx.thr, enc_ctx.idx_buf, (duk_size_t) (enc_ctx.ptr - enc_ctx.buf));
31711 duk_replace(thr, idx);
31712}
31713
31714DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
31715 duk_cbor_decode_context dec_ctx;
31716
31717 DUK_UNREF(decode_flags);
31718
31719 /* Suppress compile warnings for functions only needed with e.g.
31720 * asserts enabled.
31721 */
31722 DUK_UNREF(duk__cbor_get_reserve);
31723
31724 idx = duk_require_normalize_index(thr, idx);
31725
31726 dec_ctx.thr = thr;
31727 dec_ctx.buf = (const duk_uint8_t *) duk_require_buffer_data(thr, idx, &dec_ctx.len);
31728 dec_ctx.off = 0;
31729 /* dec_ctx.len: set above */
31730
31731 dec_ctx.recursion_depth = 0;
31732 dec_ctx.recursion_limit = DUK_USE_CBOR_DEC_RECLIMIT;
31733
31734 duk__cbor_decode_req_stack(&dec_ctx);
31735 duk__cbor_decode_value(&dec_ctx);
31736 DUK_ASSERT(dec_ctx.recursion_depth == 0);
31737 if (dec_ctx.off != dec_ctx.len) {
31738 (void) duk_type_error(thr, "trailing garbage");
31739 }
31740
31741 duk_replace(thr, idx);
31742}
31743
31744#else /* DUK_USE_CBOR_SUPPORT */
31745
31746DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
31747 DUK_UNREF(idx);
31748 DUK_UNREF(encode_flags);
31749 DUK_ERROR_UNSUPPORTED(thr);
31750}
31751
31752DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
31753 DUK_UNREF(idx);
31754 DUK_UNREF(decode_flags);
31755 DUK_ERROR_UNSUPPORTED(thr);
31756}
31757
31758#endif /* DUK_USE_CBOR_SUPPORT */
31759
31760/*
31761 * Public APIs
31762 */
31763
31764DUK_EXTERNAL void duk_cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
31765 DUK_ASSERT_API_ENTRY(thr);
31766 duk__cbor_encode(thr, idx, encode_flags);
31767}
31768DUK_EXTERNAL void duk_cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
31769 DUK_ASSERT_API_ENTRY(thr);
31770 duk__cbor_decode(thr, idx, decode_flags);
31771}
31772
31773#if defined(DUK_USE_CBOR_BUILTIN)
31774#if defined(DUK_USE_CBOR_SUPPORT)
31775DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) {
31776 DUK_ASSERT_TOP(thr, 1);
31777
31778 duk__cbor_encode(thr, -1, 0 /*flags*/);
31779
31780 /* Produce an ArrayBuffer by first decoding into a plain buffer which
31781 * mimics a Uint8Array and gettings its .buffer property.
31782 */
31783 /* XXX: shortcut */
31784 (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_LC_BUFFER);
31785 return 1;
31786}
31787
31788DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) {
31789 DUK_ASSERT_TOP(thr, 1);
31790
31791 duk__cbor_decode(thr, -1, 0 /*flags*/);
31792 return 1;
31793}
31794#else /* DUK_USE_CBOR_SUPPORT */
31795DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) {
31796 DUK_ERROR_UNSUPPORTED(thr);
31797 DUK_WO_NORETURN(return 0;);
31798}
31799DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) {
31800 DUK_ERROR_UNSUPPORTED(thr);
31801 DUK_WO_NORETURN(return 0;);
31802}
31803#endif /* DUK_USE_CBOR_SUPPORT */
31804#endif /* DUK_USE_CBOR_BUILTIN */
31805
31806/* automatic undefs */
31807#undef DUK__CBOR_AI
31808#line 1 "duk_bi_date.c"
31809/*
31810 * Date built-ins
31811 *
31812 * Unlike most built-ins, Date has some platform dependencies for getting
31813 * UTC time, converting between UTC and local time, and parsing and
31814 * formatting time values. These are all abstracted behind DUK_USE_xxx
31815 * config options. There are built-in platform specific providers for
31816 * POSIX and Windows, but external providers can also be used.
31817 *
31818 * See doc/datetime.rst.
31819 *
31820 */
31821
31822/* #include duk_internal.h -> already included */
31823
31824/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */
31825
31826/*
31827 * Forward declarations
31828 */
31829
31830DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset);
31831DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags);
31832DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val);
31833DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags);
31834
31835/*
31836 * Other file level defines
31837 */
31838
31839/* Debug macro to print all parts and dparts (used manually because of debug level). */
31840#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \
31841 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
31842 (long) (parts)[0], (long) (parts)[1], \
31843 (long) (parts)[2], (long) (parts)[3], \
31844 (long) (parts)[4], (long) (parts)[5], \
31845 (long) (parts)[6], (long) (parts)[7], \
31846 (double) (dparts)[0], (double) (dparts)[1], \
31847 (double) (dparts)[2], (double) (dparts)[3], \
31848 (double) (dparts)[4], (double) (dparts)[5], \
31849 (double) (dparts)[6], (double) (dparts)[7])); \
31850 } while (0)
31851#define DUK__DPRINT_PARTS(parts) do { \
31852 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
31853 (long) (parts)[0], (long) (parts)[1], \
31854 (long) (parts)[2], (long) (parts)[3], \
31855 (long) (parts)[4], (long) (parts)[5], \
31856 (long) (parts)[6], (long) (parts)[7])); \
31857 } while (0)
31858#define DUK__DPRINT_DPARTS(dparts) do { \
31859 DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
31860 (double) (dparts)[0], (double) (dparts)[1], \
31861 (double) (dparts)[2], (double) (dparts)[3], \
31862 (double) (dparts)[4], (double) (dparts)[5], \
31863 (double) (dparts)[6], (double) (dparts)[7])); \
31864 } while (0)
31865
31866/* Equivalent year for DST calculations outside [1970,2038[ range, see
31867 * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and
31868 * starts with the same weekday on Jan 1.
31869 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
31870 */
31871#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
31872DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
31873#if 1
31874 /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py):
31875 * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
31876 */
31877
31878 /* non-leap year: sunday, monday, ... */
31879 DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
31880 DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
31881
31882 /* leap year: sunday, monday, ... */
31883 DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
31884 DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
31885#endif
31886
31887#if 0
31888 /* This is based on Rhino EquivalentYear() algorithm:
31889 * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
31890 */
31891
31892 /* non-leap year: sunday, monday, ... */
31893 DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
31894 DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
31895
31896 /* leap year: sunday, monday, ... */
31897 DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
31898 DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
31899#endif
31900};
31901
31902/*
31903 * ISO 8601 subset parser.
31904 */
31905
31906/* Parser part count. */
31907#define DUK__NUM_ISO8601_PARSER_PARTS 9
31908
31909/* Parser part indices. */
31910#define DUK__PI_YEAR 0
31911#define DUK__PI_MONTH 1
31912#define DUK__PI_DAY 2
31913#define DUK__PI_HOUR 3
31914#define DUK__PI_MINUTE 4
31915#define DUK__PI_SECOND 5
31916#define DUK__PI_MILLISECOND 6
31917#define DUK__PI_TZHOUR 7
31918#define DUK__PI_TZMINUTE 8
31919
31920/* Parser part masks. */
31921#define DUK__PM_YEAR (1 << DUK__PI_YEAR)
31922#define DUK__PM_MONTH (1 << DUK__PI_MONTH)
31923#define DUK__PM_DAY (1 << DUK__PI_DAY)
31924#define DUK__PM_HOUR (1 << DUK__PI_HOUR)
31925#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE)
31926#define DUK__PM_SECOND (1 << DUK__PI_SECOND)
31927#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND)
31928#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR)
31929#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE)
31930
31931/* Parser separator indices. */
31932#define DUK__SI_PLUS 0
31933#define DUK__SI_MINUS 1
31934#define DUK__SI_T 2
31935#define DUK__SI_SPACE 3
31936#define DUK__SI_COLON 4
31937#define DUK__SI_PERIOD 5
31938#define DUK__SI_Z 6
31939#define DUK__SI_NUL 7
31940
31941/* Parser separator masks. */
31942#define DUK__SM_PLUS (1 << DUK__SI_PLUS)
31943#define DUK__SM_MINUS (1 << DUK__SI_MINUS)
31944#define DUK__SM_T (1 << DUK__SI_T)
31945#define DUK__SM_SPACE (1 << DUK__SI_SPACE)
31946#define DUK__SM_COLON (1 << DUK__SI_COLON)
31947#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD)
31948#define DUK__SM_Z (1 << DUK__SI_Z)
31949#define DUK__SM_NUL (1 << DUK__SI_NUL)
31950
31951/* Rule control flags. */
31952#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */
31953#define DUK__CF_ACCEPT (1 << 1) /* accept string */
31954#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */
31955
31956#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \
31957 ((duk_uint32_t) (partmask) + \
31958 (((duk_uint32_t) (sepmask)) << 9) + \
31959 (((duk_uint32_t) (nextpart)) << 17) + \
31960 (((duk_uint32_t) (flags)) << 21))
31961
31962#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \
31963 (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
31964 (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
31965 } while (0)
31966
31967#define DUK__RULE_MASK_PART_SEP 0x1ffffUL
31968
31969/* Matching separator index is used in the control table */
31970DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
31971 DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
31972 DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
31973};
31974
31975/* Rule table: first matching rule is used to determine what to do next. */
31976DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
31977 DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
31978 DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
31979 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
31980 DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
31981 DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
31982 DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
31983 DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
31984 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_PLUS, DUK__PI_TZHOUR, 0),
31985 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_MINUS, DUK__PI_TZHOUR, DUK__CF_NEG),
31986 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_Z, 0, DUK__CF_ACCEPT_NUL),
31987 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND | DUK__PM_TZHOUR /*Note2*/ | DUK__PM_TZMINUTE, DUK__SM_NUL, 0, DUK__CF_ACCEPT)
31988
31989 /* Note1: the specification doesn't require matching a time form with
31990 * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
31991 *
31992 * Note2: the specification doesn't require matching a timezone offset
31993 * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
31994 */
31995};
31996
31997DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) {
31998 duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
31999 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
32000 duk_double_t d;
32001 const duk_uint8_t *p;
32002 duk_small_uint_t part_idx = 0;
32003 duk_int_t accum = 0;
32004 duk_small_uint_t ndigits = 0;
32005 duk_bool_t neg_year = 0;
32006 duk_bool_t neg_tzoffset = 0;
32007 duk_uint_fast8_t ch;
32008 duk_small_uint_t i;
32009
32010 /* During parsing, month and day are one-based; set defaults here. */
32011 duk_memzero(parts, sizeof(parts));
32012 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
32013 parts[DUK_DATE_IDX_MONTH] = 1;
32014 parts[DUK_DATE_IDX_DAY] = 1;
32015
32016 /* Special handling for year sign. */
32017 p = (const duk_uint8_t *) str;
32018 ch = p[0];
32019 if (ch == DUK_ASC_PLUS) {
32020 p++;
32021 } else if (ch == DUK_ASC_MINUS) {
32022 neg_year = 1;
32023 p++;
32024 }
32025
32026 for (;;) {
32027 ch = *p++;
32028 DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
32029 (long) part_idx, (long) ch,
32030 (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
32031
32032 if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
32033 if (ndigits >= 9) {
32034 DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
32035 goto reject;
32036 }
32037 if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) {
32038 /* ignore millisecond fractions after 3 */
32039 } else {
32040 accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
32041 ndigits++;
32042 }
32043 } else {
32044 duk_uint_fast32_t match_val;
32045 duk_small_uint_t sep_idx;
32046
32047 if (ndigits <= 0) {
32048 goto reject;
32049 }
32050 if (part_idx == DUK__PI_MILLISECOND) {
32051 /* complete the millisecond field */
32052 while (ndigits < 3) {
32053 accum *= 10;
32054 ndigits++;
32055 }
32056 }
32057 parts[part_idx] = accum;
32058 DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
32059
32060 accum = 0;
32061 ndigits = 0;
32062
32063 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
32064 if (duk__parse_iso8601_seps[i] == ch) {
32065 break;
32066 }
32067 }
32068 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
32069 DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
32070 goto reject;
32071 }
32072
32073 sep_idx = i;
32074 match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */
32075
32076 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
32077 duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
32078 duk_small_uint_t nextpart;
32079 duk_small_uint_t cflags;
32080
32081 DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
32082 (long) part_idx, (long) sep_idx,
32083 (unsigned long) match_val, (unsigned long) rule));
32084
32085 if ((rule & match_val) != match_val) {
32086 continue;
32087 }
32088
32089 DUK__UNPACK_RULE(rule, nextpart, cflags);
32090
32091 DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
32092 "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
32093 (long) part_idx, (long) sep_idx,
32094 (unsigned long) match_val, (unsigned long) rule,
32095 (long) nextpart, (unsigned long) cflags));
32096
32097 if (cflags & DUK__CF_NEG) {
32098 neg_tzoffset = 1;
32099 }
32100
32101 if (cflags & DUK__CF_ACCEPT) {
32102 goto accept;
32103 }
32104
32105 if (cflags & DUK__CF_ACCEPT_NUL) {
32106 DUK_ASSERT(*(p - 1) != (char) 0);
32107 if (*p == DUK_ASC_NUL) {
32108 goto accept;
32109 }
32110 goto reject;
32111 }
32112
32113 part_idx = nextpart;
32114 break;
32115 } /* rule match */
32116
32117 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
32118 DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
32119 goto reject;
32120 }
32121
32122 if (ch == 0) {
32123 /* This shouldn't be necessary, but check just in case
32124 * to avoid any chance of overruns.
32125 */
32126 DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
32127 goto reject;
32128 }
32129 } /* if-digit-else-ctrl */
32130 } /* char loop */
32131
32132 /* We should never exit the loop above. */
32133 DUK_UNREACHABLE();
32134
32135 reject:
32136 DUK_DDD(DUK_DDDPRINT("reject"));
32137 return 0;
32138
32139 accept:
32140 DUK_DDD(DUK_DDDPRINT("accept"));
32141
32142 /* Apply timezone offset to get the main parts in UTC */
32143 if (neg_year) {
32144 parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
32145 }
32146 if (neg_tzoffset) {
32147 parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
32148 parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
32149 } else {
32150 parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
32151 parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
32152 }
32153 parts[DUK__PI_MONTH] -= 1; /* zero-based month */
32154 parts[DUK__PI_DAY] -= 1; /* zero-based day */
32155
32156 /* Use double parts, they tolerate unnormalized time.
32157 *
32158 * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
32159 * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
32160 * but will make the value initialized just in case, and avoid any
32161 * potential for Valgrind issues.
32162 */
32163 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
32164 DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
32165 dparts[i] = parts[i];
32166 }
32167
32168 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
32169 duk_push_number(thr, d);
32170 return 1;
32171}
32172
32173/*
32174 * Date/time parsing helper.
32175 *
32176 * Parse a datetime string into a time value. We must first try to parse
32177 * the input according to the standard format in E5.1 Section 15.9.1.15.
32178 * If that fails, we can try to parse using custom parsing, which can
32179 * either be platform neutral (custom code) or platform specific (using
32180 * existing platform API calls).
32181 *
32182 * Note in particular that we must parse whatever toString(), toUTCString(),
32183 * and toISOString() can produce; see E5.1 Section 15.9.4.2.
32184 *
32185 * Returns 1 to allow tail calling.
32186 *
32187 * There is much room for improvement here with respect to supporting
32188 * alternative datetime formats. For instance, V8 parses '2012-01-01' as
32189 * UTC and '2012/01/01' as local time.
32190 */
32191
32192DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) {
32193 /* XXX: there is a small risk here: because the ISO 8601 parser is
32194 * very loose, it may end up parsing some datetime values which
32195 * would be better parsed with a platform specific parser.
32196 */
32197
32198 DUK_ASSERT(str != NULL);
32199 DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
32200
32201 if (duk__parse_string_iso8601_subset(thr, str) != 0) {
32202 return 1;
32203 }
32204
32205#if defined(DUK_USE_DATE_PARSE_STRING)
32206 /* Contract, either:
32207 * - Push value on stack and return 1
32208 * - Don't push anything on stack and return 0
32209 */
32210
32211 if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) {
32212 return 1;
32213 }
32214#else
32215 /* No platform-specific parsing, this is not an error. */
32216#endif
32217
32218 duk_push_nan(thr);
32219 return 1;
32220}
32221
32222/*
32223 * Calendar helpers
32224 *
32225 * Some helpers are used for getters and can operate on normalized values
32226 * which can be represented with 32-bit signed integers. Other helpers are
32227 * needed by setters and operate on un-normalized double values, must watch
32228 * out for non-finite numbers etc.
32229 */
32230
32231DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
32232 (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
32233 (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
32234 (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
32235};
32236
32237/* Maximum iteration count for computing UTC-to-local time offset when
32238 * creating an ECMAScript time value from local parts.
32239 */
32240#define DUK__LOCAL_TZOFFSET_MAXITER 4
32241
32242/* Because 'day since epoch' can be negative and is used to compute weekday
32243 * using a modulo operation, add this multiple of 7 to avoid negative values
32244 * when year is below 1970 epoch. ECMAScript time values are restricted to
32245 * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
32246 * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
32247 */
32248#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */
32249
32250DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
32251 if ((year % 4) != 0) {
32252 return 0;
32253 }
32254 if ((year % 100) != 0) {
32255 return 1;
32256 }
32257 if ((year % 400) != 0) {
32258 return 0;
32259 }
32260 return 1;
32261}
32262
32263DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
32264 return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
32265}
32266
32267DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
32268 return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
32269}
32270
32271DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
32272 return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
32273}
32274
32275DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
32276 if (!DUK_ISFINITE(x)) {
32277 return DUK_DOUBLE_NAN;
32278 }
32279
32280 if (!duk_bi_date_timeval_in_valid_range(x)) {
32281 return DUK_DOUBLE_NAN;
32282 }
32283
32284 x = duk_js_tointeger_number(x);
32285
32286 /* Here we'd have the option to normalize -0 to +0. */
32287 return x;
32288}
32289
32290/* Integer division which floors also negative values correctly. */
32291DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
32292 DUK_ASSERT(b > 0);
32293 if (a >= 0) {
32294 return a / b;
32295 } else {
32296 /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1
32297 * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1
32298 * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2
32299 */
32300 return (a - b + 1) / b;
32301 }
32302}
32303
32304/* Compute day number of the first day of a given year. */
32305DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
32306 /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
32307 * values, but is incorrect for negative ones.
32308 */
32309 return 365 * (year - 1970)
32310 + duk__div_floor(year - 1969, 4)
32311 - duk__div_floor(year - 1901, 100)
32312 + duk__div_floor(year - 1601, 400);
32313}
32314
32315/* Given a day number, determine year and day-within-year. */
32316DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
32317 duk_int_t year;
32318 duk_int_t diff_days;
32319
32320 /* estimate year upwards (towards positive infinity), then back down;
32321 * two iterations should be enough
32322 */
32323
32324 if (day >= 0) {
32325 year = 1970 + day / 365;
32326 } else {
32327 year = 1970 + day / 366;
32328 }
32329
32330 for (;;) {
32331 diff_days = duk__day_from_year(year) - day;
32332 DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
32333 if (diff_days <= 0) {
32334 DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */
32335 *out_day_within_year = -diff_days;
32336 DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
32337 (long) year, (long) *out_day_within_year));
32338 DUK_ASSERT(*out_day_within_year >= 0);
32339 DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
32340 return year;
32341 }
32342
32343 /* Note: this is very tricky; we must never 'overshoot' the
32344 * correction downwards.
32345 */
32346 year -= 1 + (diff_days - 1) / 366; /* conservative */
32347 }
32348}
32349
32350/* Given a (year, month, day-within-month) triple, compute day number.
32351 * The input triple is un-normalized and may contain non-finite values.
32352 */
32353DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
32354 duk_int_t day_num;
32355 duk_bool_t is_leap;
32356 duk_small_int_t i, n;
32357
32358 /* Assume that year, month, day are all coerced to whole numbers.
32359 * They may also be NaN or infinity, in which case this function
32360 * must return NaN or infinity to ensure time value becomes NaN.
32361 * If 'day' is NaN, the final return will end up returning a NaN,
32362 * so it doesn't need to be checked here.
32363 */
32364
32365 if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
32366 return DUK_DOUBLE_NAN;
32367 }
32368
32369 year += DUK_FLOOR(month / 12.0);
32370
32371 month = DUK_FMOD(month, 12.0);
32372 if (month < 0.0) {
32373 /* handle negative values */
32374 month += 12.0;
32375 }
32376
32377 /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
32378 * does not normalize the day-of-month (nor check whether or not
32379 * it is finite) because it's not necessary for finding the day
32380 * number which matches the (year,month) pair.
32381 *
32382 * We assume that duk__day_from_year() is exact here.
32383 *
32384 * Without an explicit infinity / NaN check in the beginning,
32385 * day_num would be a bogus integer here.
32386 *
32387 * It's possible for 'year' to be out of integer range here.
32388 * If so, we need to return NaN without integer overflow.
32389 * This fixes test-bug-setyear-overflow.js.
32390 */
32391
32392 if (!duk_bi_date_year_in_valid_range(year)) {
32393 DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
32394 return DUK_DOUBLE_NAN;
32395 }
32396 day_num = duk__day_from_year((duk_int_t) year);
32397 is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
32398
32399 n = (duk_small_int_t) month;
32400 for (i = 0; i < n; i++) {
32401 day_num += duk__days_in_month[i];
32402 if (i == 1 && is_leap) {
32403 day_num++;
32404 }
32405 }
32406
32407 /* If 'day' is NaN, returns NaN. */
32408 return (duk_double_t) day_num + day;
32409}
32410
32411/* Split time value into parts. The time value may contain fractions (it may
32412 * come from duk_time_to_components() API call) which are truncated. Possible
32413 * local time adjustment has already been applied when reading the time value.
32414 */
32415DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) {
32416 duk_double_t d1, d2;
32417 duk_int_t t1, t2;
32418 duk_int_t day_since_epoch;
32419 duk_int_t year; /* does not fit into 16 bits */
32420 duk_small_int_t day_in_year;
32421 duk_small_int_t month;
32422 duk_small_int_t day;
32423 duk_small_int_t dim;
32424 duk_int_t jan1_since_epoch;
32425 duk_small_int_t jan1_weekday;
32426 duk_int_t equiv_year;
32427 duk_small_uint_t i;
32428 duk_bool_t is_leap;
32429 duk_small_int_t arridx;
32430
32431 DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
32432 d = DUK_FLOOR(d); /* remove fractions if present */
32433 DUK_ASSERT(duk_double_equals(DUK_FLOOR(d), d));
32434
32435 /* The timevalue must be in valid ECMAScript range, but since a local
32436 * time offset can be applied, we need to allow a +/- 24h leeway to
32437 * the value. In other words, although the UTC time is within the
32438 * ECMAScript range, the local part values can be just outside of it.
32439 */
32440 DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
32441 DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
32442
32443 /* These computations are guaranteed to be exact for the valid
32444 * E5 time value range, assuming milliseconds without fractions.
32445 */
32446 d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
32447 if (d1 < 0.0) {
32448 /* deal with negative values */
32449 d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
32450 }
32451 d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
32452 DUK_ASSERT(duk_double_equals(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1, d));
32453 /* now expected to fit into a 32-bit integer */
32454 t1 = (duk_int_t) d1;
32455 t2 = (duk_int_t) d2;
32456 day_since_epoch = t2;
32457 DUK_ASSERT(duk_double_equals((duk_double_t) t1, d1));
32458 DUK_ASSERT(duk_double_equals((duk_double_t) t2, d2));
32459
32460 /* t1 = milliseconds within day (fits 32 bit)
32461 * t2 = day number from epoch (fits 32 bit, may be negative)
32462 */
32463
32464 parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
32465 parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
32466 parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
32467 parts[DUK_DATE_IDX_HOUR] = t1;
32468 DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
32469 DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
32470 DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
32471 DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
32472
32473 DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
32474 (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
32475 (long) parts[DUK_DATE_IDX_HOUR],
32476 (long) parts[DUK_DATE_IDX_MINUTE],
32477 (long) parts[DUK_DATE_IDX_SECOND],
32478 (long) parts[DUK_DATE_IDX_MILLISECOND]));
32479
32480 /* This assert depends on the input parts representing time inside
32481 * the ECMAScript range.
32482 */
32483 DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
32484 parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
32485 DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
32486
32487 year = duk__year_from_day(t2, &day_in_year);
32488 day = day_in_year;
32489 is_leap = duk_bi_date_is_leap_year(year);
32490 for (month = 0; month < 12; month++) {
32491 dim = duk__days_in_month[month];
32492 if (month == 1 && is_leap) {
32493 dim++;
32494 }
32495 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
32496 (long) month, (long) dim, (long) day));
32497 if (day < dim) {
32498 break;
32499 }
32500 day -= dim;
32501 }
32502 DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
32503 DUK_ASSERT(month >= 0 && month <= 11);
32504 DUK_ASSERT(day >= 0 && day <= 31);
32505
32506 /* Equivalent year mapping, used to avoid DST trouble when platform
32507 * may fail to provide reasonable DST answers for dates outside the
32508 * ordinary range (e.g. 1970-2038). An equivalent year has the same
32509 * leap-year-ness as the original year and begins on the same weekday
32510 * (Jan 1).
32511 *
32512 * The year 2038 is avoided because there seem to be problems with it
32513 * on some platforms. The year 1970 is also avoided as there were
32514 * practical problems with it; an equivalent year is used for it too,
32515 * which breaks some DST computations for 1970 right now, see e.g.
32516 * test-bi-date-tzoffset-brute-fi.js.
32517 */
32518 if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
32519 DUK_ASSERT(is_leap == 0 || is_leap == 1);
32520
32521 jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
32522 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
32523 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
32524 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
32525 arridx = jan1_weekday;
32526 if (is_leap) {
32527 arridx += 7;
32528 }
32529 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
32530
32531 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
32532 year = equiv_year;
32533 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
32534 "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
32535 (long) year, (long) day_in_year, (long) day_since_epoch,
32536 (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
32537 }
32538
32539 parts[DUK_DATE_IDX_YEAR] = year;
32540 parts[DUK_DATE_IDX_MONTH] = month;
32541 parts[DUK_DATE_IDX_DAY] = day;
32542
32543 if (flags & DUK_DATE_FLAG_ONEBASED) {
32544 parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */
32545 parts[DUK_DATE_IDX_DAY]++; /* -""- */
32546 }
32547
32548 if (dparts != NULL) {
32549 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
32550 dparts[i] = (duk_double_t) parts[i];
32551 }
32552 }
32553}
32554
32555/* Compute time value from (double) parts. The parts can be either UTC
32556 * or local time; if local, they need to be (conceptually) converted into
32557 * UTC time. The parts may represent valid or invalid time, and may be
32558 * wildly out of range (but may cancel each other and still come out in
32559 * the valid Date range).
32560 */
32561DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
32562#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
32563 /* See comments below on MakeTime why these are volatile. */
32564 volatile duk_double_t tmp_time;
32565 volatile duk_double_t tmp_day;
32566 volatile duk_double_t d;
32567#else
32568 duk_double_t tmp_time;
32569 duk_double_t tmp_day;
32570 duk_double_t d;
32571#endif
32572 duk_small_uint_t i;
32573 duk_int_t tzoff, tzoffprev1, tzoffprev2;
32574
32575 /* Expects 'this' at top of stack on entry. */
32576
32577 /* Coerce all finite parts with ToInteger(). ToInteger() must not
32578 * be called for NaN/Infinity because it will convert e.g. NaN to
32579 * zero. If ToInteger() has already been called, this has no side
32580 * effects and is idempotent.
32581 *
32582 * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
32583 * issues if the value is uninitialized.
32584 */
32585 for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
32586 /* SCANBUILD: scan-build complains here about assigned value
32587 * being garbage or undefined. This is correct but operating
32588 * on undefined values has no ill effect and is ignored by the
32589 * caller in the case where this happens.
32590 */
32591 d = dparts[i];
32592 if (DUK_ISFINITE(d)) {
32593 dparts[i] = duk_js_tointeger_number(d);
32594 }
32595 }
32596
32597 /* Use explicit steps in computation to try to ensure that
32598 * computation happens with intermediate results coerced to
32599 * double values (instead of using something more accurate).
32600 * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
32601 * rules (= ECMAScript '+' and '*' operators).
32602 *
32603 * Without 'volatile' even this approach fails on some platform
32604 * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
32605 * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
32606 * would fail because of some optimizations when computing tmp_time
32607 * (MakeTime below). Adding 'volatile' to tmp_time solved this
32608 * particular problem (annoyingly, also adding debug prints or
32609 * running the executable under valgrind hides it).
32610 */
32611
32612 /* MakeTime */
32613 tmp_time = 0.0;
32614 tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
32615 tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
32616 tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
32617 tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
32618
32619 /* MakeDay */
32620 tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
32621
32622 /* MakeDate */
32623 d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
32624
32625 DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
32626 (double) tmp_time, (double) tmp_day, (double) d));
32627
32628 /* Optional UTC conversion. */
32629 if (flags & DUK_DATE_FLAG_LOCALTIME) {
32630 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
32631 * time value computed from UTC parts. At this point we only
32632 * have 'd' which is a time value computed from local parts, so
32633 * it is off by the UTC-to-local time offset which we don't know
32634 * yet. The current solution for computing the UTC-to-local
32635 * time offset is to iterate a few times and detect a fixed
32636 * point or a two-cycle loop (or a sanity iteration limit),
32637 * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
32638 *
32639 * E5.1 Section 15.9.1.9:
32640 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
32641 *
32642 * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
32643 */
32644
32645#if 0
32646 /* Old solution: don't iterate, incorrect */
32647 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
32648 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
32649 d -= tzoff * 1000L;
32650 DUK_UNREF(tzoffprev1);
32651 DUK_UNREF(tzoffprev2);
32652#endif
32653
32654 /* Iteration solution */
32655 tzoff = 0;
32656 tzoffprev1 = 999999999L; /* invalid value which never matches */
32657 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
32658 tzoffprev2 = tzoffprev1;
32659 tzoffprev1 = tzoff;
32660 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
32661 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
32662 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
32663 if (tzoff == tzoffprev1) {
32664 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
32665 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
32666 break;
32667 } else if (tzoff == tzoffprev2) {
32668 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
32669 * In these cases, favor a higher tzoffset to get a consistent
32670 * result which is independent of iteration count. Not sure if
32671 * this is a generically correct solution.
32672 */
32673 DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
32674 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
32675 if (tzoffprev1 > tzoff) {
32676 tzoff = tzoffprev1;
32677 }
32678 break;
32679 }
32680 }
32681 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
32682 d -= tzoff * 1000L;
32683 }
32684
32685 /* TimeClip(), which also handles Infinity -> NaN conversion */
32686 d = duk__timeclip(d);
32687
32688 return d;
32689}
32690
32691/*
32692 * API oriented helpers
32693 */
32694
32695/* Push 'this' binding, check that it is a Date object; then push the
32696 * internal time value. At the end, stack is: [ ... this timeval ].
32697 * Returns the time value. Local time adjustment is done if requested.
32698 */
32699DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
32700 duk_hobject *h;
32701 duk_double_t d;
32702 duk_int_t tzoffset = 0;
32703
32704 duk_push_this(thr);
32705 h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */
32706 if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
32707 DUK_ERROR_TYPE(thr, "expected Date");
32708 DUK_WO_NORETURN(return 0.0;);
32709 }
32710
32711 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
32712 d = duk_to_number_m1(thr);
32713 duk_pop(thr);
32714
32715 if (DUK_ISNAN(d)) {
32716 if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
32717 d = 0.0;
32718 }
32719 if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
32720 DUK_ERROR_RANGE(thr, "Invalid Date");
32721 DUK_WO_NORETURN(return 0.0;);
32722 }
32723 }
32724 /* if no NaN handling flag, may still be NaN here, but not Inf */
32725 DUK_ASSERT(!DUK_ISINF(d));
32726
32727 if (flags & DUK_DATE_FLAG_LOCALTIME) {
32728 /* Note: DST adjustment is determined using UTC time.
32729 * If 'd' is NaN, tzoffset will be 0.
32730 */
32731 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */
32732 d += tzoffset * 1000L;
32733 }
32734 if (out_tzoffset) {
32735 *out_tzoffset = tzoffset;
32736 }
32737
32738 /* [ ... this ] */
32739 return d;
32740}
32741
32742DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) {
32743 return duk__push_this_get_timeval_tzoffset(thr, flags, NULL);
32744}
32745
32746/* Set timeval to 'this' from dparts, push the new time value onto the
32747 * value stack and return 1 (caller can then tail call us). Expects
32748 * the value stack to contain 'this' on the stack top.
32749 */
32750DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) {
32751 duk_double_t d;
32752
32753 /* [ ... this ] */
32754
32755 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
32756 duk_push_number(thr, d); /* -> [ ... this timeval_new ] */
32757 duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */
32758
32759 /* Must force write because e.g. .setYear() must work even when
32760 * the Date instance is frozen.
32761 */
32762 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
32763
32764 /* Stack top: new time value, return 1 to allow tail calls. */
32765 return 1;
32766}
32767
32768/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
32769DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
32770 char yearstr[8]; /* "-123456\0" */
32771 char tzstr[8]; /* "+11:22\0" */
32772 char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
32773
32774 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
32775 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
32776 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
32777
32778 /* Note: %06d for positive value, %07d for negative value to include
32779 * sign and 6 digits.
32780 */
32781 DUK_SNPRINTF(yearstr,
32782 sizeof(yearstr),
32783 (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
32784 ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
32785 (long) parts[DUK_DATE_IDX_YEAR]);
32786 yearstr[sizeof(yearstr) - 1] = (char) 0;
32787
32788 if (flags & DUK_DATE_FLAG_LOCALTIME) {
32789 /* tzoffset seconds are dropped; 16 bits suffice for
32790 * time offset in minutes
32791 */
32792 const char *fmt;
32793 duk_small_int_t tmp, arg_hours, arg_minutes;
32794
32795 if (tzoffset >= 0) {
32796 tmp = tzoffset;
32797 fmt = "+%02d:%02d";
32798 } else {
32799 tmp = -tzoffset;
32800 fmt = "-%02d:%02d";
32801 }
32802 tmp = tmp / 60;
32803 arg_hours = tmp / 60;
32804 arg_minutes = tmp % 60;
32805 DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */
32806 arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */
32807
32808 DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes);
32809 tzstr[sizeof(tzstr) - 1] = (char) 0;
32810 } else {
32811 tzstr[0] = DUK_ASC_UC_Z;
32812 tzstr[1] = (char) 0;
32813 }
32814
32815 /* Unlike year, the other parts fit into 16 bits so %d format
32816 * is portable.
32817 */
32818 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
32819 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
32820 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
32821 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
32822 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
32823 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
32824 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
32825 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
32826 } else {
32827 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
32828 DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
32829 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
32830 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
32831 (const char *) tzstr);
32832 }
32833}
32834
32835/* Helper for string conversion calls: check 'this' binding, get the
32836 * internal time value, and format date and/or time in a few formats.
32837 * Return value allows tail calls.
32838 */
32839DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) {
32840 duk_double_t d;
32841 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
32842 duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
32843 duk_bool_t rc;
32844 duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
32845
32846 DUK_UNREF(rc); /* unreferenced with some options */
32847
32848 d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset);
32849 if (DUK_ISNAN(d)) {
32850 duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE);
32851 return 1;
32852 }
32853 DUK_ASSERT(DUK_ISFINITE(d));
32854
32855 /* formatters always get one-based month/day-of-month */
32856 duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
32857 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
32858 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
32859
32860 if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
32861 /* try locale specific formatter; if it refuses to format the
32862 * string, fall back to an ISO 8601 formatted value in local
32863 * time.
32864 */
32865#if defined(DUK_USE_DATE_FORMAT_STRING)
32866 /* Contract, either:
32867 * - Push string to value stack and return 1
32868 * - Don't push anything and return 0
32869 */
32870
32871 rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags);
32872 if (rc != 0) {
32873 return 1;
32874 }
32875#else
32876 /* No locale specific formatter; this is OK, we fall back
32877 * to ISO 8601.
32878 */
32879#endif
32880 }
32881
32882 /* Different calling convention than above used because the helper
32883 * is shared.
32884 */
32885 duk__format_parts_iso8601(parts, tzoffset, flags, buf);
32886 duk_push_string(thr, (const char *) buf);
32887 return 1;
32888}
32889
32890/* Helper for component getter calls: check 'this' binding, get the
32891 * internal time value, split it into parts (either as UTC time or
32892 * local time), push a specified component as a return value to the
32893 * value stack and return 1 (caller can then tail call us).
32894 */
32895DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) {
32896 duk_double_t d;
32897 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
32898 duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
32899
32900 DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
32901 DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
32902
32903 d = duk__push_this_get_timeval(thr, flags_and_idx);
32904 if (DUK_ISNAN(d)) {
32905 duk_push_nan(thr);
32906 return 1;
32907 }
32908 DUK_ASSERT(DUK_ISFINITE(d));
32909
32910 duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */
32911
32912 /* Setter APIs detect special year numbers (0...99) and apply a +1900
32913 * only in certain cases. The legacy getYear() getter applies -1900
32914 * unconditionally.
32915 */
32916 duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
32917 return 1;
32918}
32919
32920/* Helper for component setter calls: check 'this' binding, get the
32921 * internal time value, split it into parts (either as UTC time or
32922 * local time), modify one or more components as specified, recompute
32923 * the time value, set it as the internal value. Finally, push the
32924 * new time value as a return value to the value stack and return 1
32925 * (caller can then tail call us).
32926 */
32927DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) {
32928 duk_double_t d;
32929 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
32930 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
32931 duk_idx_t nargs;
32932 duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
32933 duk_small_uint_t idx_first, idx;
32934 duk_small_uint_t i;
32935
32936 nargs = duk_get_top(thr);
32937 d = duk__push_this_get_timeval(thr, flags_and_maxnargs);
32938 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
32939
32940 if (DUK_ISFINITE(d)) {
32941 duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
32942 } else {
32943 /* NaN timevalue: we need to coerce the arguments, but
32944 * the resulting internal timestamp needs to remain NaN.
32945 * This works but is not pretty: parts and dparts will
32946 * be partially uninitialized, but we only write to them.
32947 */
32948 }
32949
32950 /*
32951 * Determining which datetime components to overwrite based on
32952 * stack arguments is a bit complicated, but important to factor
32953 * out from setters themselves for compactness.
32954 *
32955 * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
32956 *
32957 * 1 -> millisecond
32958 * 2 -> second, [millisecond]
32959 * 3 -> minute, [second], [millisecond]
32960 * 4 -> hour, [minute], [second], [millisecond]
32961 *
32962 * Else:
32963 *
32964 * 1 -> date
32965 * 2 -> month, [date]
32966 * 3 -> year, [month], [date]
32967 *
32968 * By comparing nargs and maxnargs (and flags) we know which
32969 * components to override. We rely on part index ordering.
32970 */
32971
32972 if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
32973 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
32974 idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
32975 } else {
32976 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
32977 idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
32978 }
32979 DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */
32980 DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
32981
32982 for (i = 0; i < maxnargs; i++) {
32983 if ((duk_idx_t) i >= nargs) {
32984 /* no argument given -> leave components untouched */
32985 break;
32986 }
32987 idx = idx_first + i;
32988 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
32989 DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
32990
32991 if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
32992 duk__twodigit_year_fixup(thr, (duk_idx_t) i);
32993 }
32994
32995 dparts[idx] = duk_to_number(thr, (duk_idx_t) i);
32996
32997 if (idx == DUK_DATE_IDX_DAY) {
32998 /* Day-of-month is one-based in the API, but zero-based
32999 * internally, so fix here. Note that month is zero-based
33000 * both in the API and internally.
33001 */
33002 /* SCANBUILD: complains about use of uninitialized values.
33003 * The complaint is correct, but operating in undefined
33004 * values here is intentional in some cases and the caller
33005 * ignores the results.
33006 */
33007 dparts[idx] -= 1.0;
33008 }
33009 }
33010
33011 /* Leaves new timevalue on stack top and returns 1, which is correct
33012 * for part setters.
33013 */
33014 if (DUK_ISFINITE(d)) {
33015 return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs);
33016 } else {
33017 /* Internal timevalue is already NaN, so don't touch it. */
33018 duk_push_nan(thr);
33019 return 1;
33020 }
33021}
33022
33023/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
33024 * 1900 and replace value at idx_val.
33025 */
33026DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) {
33027 duk_double_t d;
33028
33029 /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
33030 * might not generate better code due to casting.
33031 */
33032
33033 /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
33034 duk_to_number(thr, idx_val);
33035 if (duk_is_nan(thr, idx_val)) {
33036 return;
33037 }
33038 duk_dup(thr, idx_val);
33039 duk_to_int(thr, -1);
33040 d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */
33041 if (d >= 0.0 && d <= 99.0) {
33042 d += 1900.0;
33043 duk_push_number(thr, d);
33044 duk_replace(thr, idx_val);
33045 }
33046 duk_pop(thr);
33047}
33048
33049/* Set datetime parts from stack arguments, defaulting any missing values.
33050 * Day-of-week is not set; it is not required when setting the time value.
33051 */
33052DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) {
33053 duk_double_t d;
33054 duk_small_uint_t i;
33055 duk_small_uint_t idx;
33056
33057 /* Causes a ToNumber() coercion, but doesn't break coercion order since
33058 * year is coerced first anyway.
33059 */
33060 duk__twodigit_year_fixup(thr, 0);
33061
33062 /* There are at most 7 args, but we use 8 here so that also
33063 * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
33064 * for any Valgrind gripes later.
33065 */
33066 for (i = 0; i < 8; i++) {
33067 /* Note: rely on index ordering */
33068 idx = DUK_DATE_IDX_YEAR + i;
33069 if ((duk_idx_t) i < nargs) {
33070 d = duk_to_number(thr, (duk_idx_t) i);
33071 if (idx == DUK_DATE_IDX_DAY) {
33072 /* Convert day from one-based to zero-based (internal). This may
33073 * cause the day part to be negative, which is OK.
33074 */
33075 d -= 1.0;
33076 }
33077 } else {
33078 /* All components default to 0 except day-of-month which defaults
33079 * to 1. However, because our internal day-of-month is zero-based,
33080 * it also defaults to zero here.
33081 */
33082 d = 0.0;
33083 }
33084 dparts[idx] = d;
33085 }
33086
33087 DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
33088 (double) dparts[0], (double) dparts[1],
33089 (double) dparts[2], (double) dparts[3],
33090 (double) dparts[4], (double) dparts[5],
33091 (double) dparts[6], (double) dparts[7]));
33092}
33093
33094/*
33095 * Indirect magic value lookup for Date methods.
33096 *
33097 * Date methods don't put their control flags into the function magic value
33098 * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the
33099 * magic value is set to an index pointing to the array of control flags
33100 * below.
33101 *
33102 * This must be kept in strict sync with genbuiltins.py!
33103 */
33104
33105static duk_uint16_t duk__date_magics[] = {
33106 /* 0: toString */
33107 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
33108
33109 /* 1: toDateString */
33110 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
33111
33112 /* 2: toTimeString */
33113 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
33114
33115 /* 3: toLocaleString */
33116 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
33117
33118 /* 4: toLocaleDateString */
33119 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
33120
33121 /* 5: toLocaleTimeString */
33122 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
33123
33124 /* 6: toUTCString */
33125 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
33126
33127 /* 7: toISOString */
33128 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
33129
33130 /* 8: getFullYear */
33131 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
33132
33133 /* 9: getUTCFullYear */
33134 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
33135
33136 /* 10: getMonth */
33137 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
33138
33139 /* 11: getUTCMonth */
33140 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
33141
33142 /* 12: getDate */
33143 DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
33144
33145 /* 13: getUTCDate */
33146 DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
33147
33148 /* 14: getDay */
33149 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
33150
33151 /* 15: getUTCDay */
33152 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
33153
33154 /* 16: getHours */
33155 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
33156
33157 /* 17: getUTCHours */
33158 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
33159
33160 /* 18: getMinutes */
33161 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
33162
33163 /* 19: getUTCMinutes */
33164 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
33165
33166 /* 20: getSeconds */
33167 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
33168
33169 /* 21: getUTCSeconds */
33170 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
33171
33172 /* 22: getMilliseconds */
33173 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
33174
33175 /* 23: getUTCMilliseconds */
33176 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
33177
33178 /* 24: setMilliseconds */
33179 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
33180
33181 /* 25: setUTCMilliseconds */
33182 DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
33183
33184 /* 26: setSeconds */
33185 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
33186
33187 /* 27: setUTCSeconds */
33188 DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
33189
33190 /* 28: setMinutes */
33191 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
33192
33193 /* 29: setUTCMinutes */
33194 DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
33195
33196 /* 30: setHours */
33197 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
33198
33199 /* 31: setUTCHours */
33200 DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
33201
33202 /* 32: setDate */
33203 DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
33204
33205 /* 33: setUTCDate */
33206 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
33207
33208 /* 34: setMonth */
33209 DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
33210
33211 /* 35: setUTCMonth */
33212 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
33213
33214 /* 36: setFullYear */
33215 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
33216
33217 /* 37: setUTCFullYear */
33218 DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
33219
33220 /* 38: getYear */
33221 DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
33222
33223 /* 39: setYear */
33224 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
33225};
33226
33227DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) {
33228 duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr);
33229 DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
33230 return (duk_small_uint_t) duk__date_magics[magicidx];
33231}
33232
33233#if defined(DUK_USE_DATE_BUILTIN)
33234/*
33235 * Constructor calls
33236 */
33237
33238DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) {
33239 duk_idx_t nargs = duk_get_top(thr);
33240 duk_bool_t is_cons = duk_is_constructor_call(thr);
33241 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
33242 duk_double_t d;
33243
33244 DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
33245
33246 (void) duk_push_object_helper(thr,
33247 DUK_HOBJECT_FLAG_EXTENSIBLE |
33248 DUK_HOBJECT_FLAG_FASTREFS |
33249 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
33250 DUK_BIDX_DATE_PROTOTYPE);
33251
33252 /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
33253 * is mutable.
33254 */
33255
33256 if (nargs == 0 || !is_cons) {
33257 d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr));
33258 duk_push_number(thr, d);
33259 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
33260 if (!is_cons) {
33261 /* called as a normal function: return new Date().toString() */
33262 duk_to_string(thr, -1);
33263 }
33264 return 1;
33265 } else if (nargs == 1) {
33266 const char *str;
33267 duk_to_primitive(thr, 0, DUK_HINT_NONE);
33268 str = duk_get_string_notsymbol(thr, 0);
33269 if (str) {
33270 duk__parse_string(thr, str);
33271 duk_replace(thr, 0); /* may be NaN */
33272 }
33273 d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */
33274 duk_push_number(thr, d);
33275 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
33276 return 1;
33277 }
33278
33279 duk__set_parts_from_args(thr, dparts, nargs);
33280
33281 /* Parts are in local time, convert when setting. */
33282
33283 (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
33284 duk_pop(thr); /* -> [ ... this ] */
33285 return 1;
33286}
33287
33288DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) {
33289 return duk__parse_string(thr, duk_to_string(thr, 0));
33290}
33291
33292DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) {
33293 duk_idx_t nargs = duk_get_top(thr);
33294 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
33295 duk_double_t d;
33296
33297 /* Behavior for nargs < 2 is implementation dependent: currently we'll
33298 * set a NaN time value (matching V8 behavior) in this case.
33299 */
33300
33301 if (nargs < 2) {
33302 duk_push_nan(thr);
33303 } else {
33304 duk__set_parts_from_args(thr, dparts, nargs);
33305 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
33306 duk_push_number(thr, d);
33307 }
33308 return 1;
33309}
33310
33311DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
33312 duk_double_t d;
33313
33314 d = duk_time_get_ecmascript_time_nofrac(thr);
33315 DUK_ASSERT(duk_double_equals(duk__timeclip(d), d)); /* TimeClip() should never be necessary */
33316 duk_push_number(thr, d);
33317 return 1;
33318}
33319
33320/*
33321 * String/JSON conversions
33322 *
33323 * Human readable conversions are now basically ISO 8601 with a space
33324 * (instead of 'T') as the date/time separator. This is a good baseline
33325 * and is platform independent.
33326 *
33327 * A shared native helper to provide many conversions. Magic value contains
33328 * a set of flags. The helper provides:
33329 *
33330 * toString()
33331 * toDateString()
33332 * toTimeString()
33333 * toLocaleString()
33334 * toLocaleDateString()
33335 * toLocaleTimeString()
33336 * toUTCString()
33337 * toISOString()
33338 *
33339 * Notes:
33340 *
33341 * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
33342 * required to be the same ECMAScript function object (!), so it is
33343 * omitted from here.
33344 *
33345 * - Date.prototype.toUTCString(): E5.1 specification does not require a
33346 * specific format, but result should be human readable. The
33347 * specification suggests using ISO 8601 format with a space (instead
33348 * of 'T') separator if a more human readable format is not available.
33349 *
33350 * - Date.prototype.toISOString(): unlike other conversion functions,
33351 * toISOString() requires a RangeError for invalid date values.
33352 */
33353
33354DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) {
33355 duk_small_uint_t flags = duk__date_get_indirect_magic(thr);
33356 return duk__to_string_helper(thr, flags);
33357}
33358
33359DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) {
33360 /* This native function is also used for Date.prototype.getTime()
33361 * as their behavior is identical.
33362 */
33363
33364 duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */
33365 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
33366 duk_push_number(thr, d);
33367 return 1;
33368}
33369
33370DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) {
33371 /* Note: toJSON() is a generic function which works even if 'this'
33372 * is not a Date. The sole argument is ignored.
33373 */
33374
33375 duk_push_this(thr);
33376 duk_to_object(thr, -1);
33377
33378 duk_dup_top(thr);
33379 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
33380 if (duk_is_number(thr, -1)) {
33381 duk_double_t d = duk_get_number(thr, -1);
33382 if (!DUK_ISFINITE(d)) {
33383 duk_push_null(thr);
33384 return 1;
33385 }
33386 }
33387 duk_pop(thr);
33388
33389 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING);
33390 duk_dup_m2(thr); /* -> [ O toIsoString O ] */
33391 duk_call_method(thr, 0);
33392 return 1;
33393}
33394
33395/*
33396 * Getters.
33397 *
33398 * Implementing getters is quite easy. The internal time value is either
33399 * NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
33400 * The internal time value can be converted to integer parts, and each
33401 * part will be normalized and will fit into a 32-bit signed integer.
33402 *
33403 * A shared native helper to provide all getters. Magic value contains
33404 * a set of flags and also packs the date component index argument. The
33405 * helper provides:
33406 *
33407 * getFullYear()
33408 * getUTCFullYear()
33409 * getMonth()
33410 * getUTCMonth()
33411 * getDate()
33412 * getUTCDate()
33413 * getDay()
33414 * getUTCDay()
33415 * getHours()
33416 * getUTCHours()
33417 * getMinutes()
33418 * getUTCMinutes()
33419 * getSeconds()
33420 * getUTCSeconds()
33421 * getMilliseconds()
33422 * getUTCMilliseconds()
33423 * getYear()
33424 *
33425 * Notes:
33426 *
33427 * - Date.prototype.getDate(): 'date' means day-of-month, and is
33428 * zero-based in internal calculations but public API expects it to
33429 * be one-based.
33430 *
33431 * - Date.prototype.getTime() and Date.prototype.valueOf() have identical
33432 * behavior. They have separate function objects, but share the same C
33433 * function (duk_bi_date_prototype_value_of).
33434 */
33435
33436DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) {
33437 duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr);
33438 return duk__get_part_helper(thr, flags_and_idx);
33439}
33440
33441DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) {
33442 /*
33443 * Return (t - LocalTime(t)) in minutes:
33444 *
33445 * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
33446 * = -(LocalTZA + DaylightSavingTA(t))
33447 *
33448 * where DaylightSavingTA() is checked for time 't'.
33449 *
33450 * Note that the sign of the result is opposite to common usage,
33451 * e.g. for EE(S)T which normally is +2h or +3h from UTC, this
33452 * function returns -120 or -180.
33453 *
33454 */
33455
33456 duk_double_t d;
33457 duk_int_t tzoffset;
33458
33459 /* Note: DST adjustment is determined using UTC time. */
33460 d = duk__push_this_get_timeval(thr, 0 /*flags*/);
33461 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
33462 if (DUK_ISNAN(d)) {
33463 duk_push_nan(thr);
33464 } else {
33465 DUK_ASSERT(DUK_ISFINITE(d));
33466 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
33467 duk_push_int(thr, -tzoffset / 60);
33468 }
33469 return 1;
33470}
33471
33472/*
33473 * Setters.
33474 *
33475 * Setters are a bit more complicated than getters. Component setters
33476 * break down the current time value into its (normalized) component
33477 * parts, replace one or more components with -unnormalized- new values,
33478 * and the components are then converted back into a time value. As an
33479 * example of using unnormalized values:
33480 *
33481 * var d = new Date(1234567890);
33482 *
33483 * is equivalent to:
33484 *
33485 * var d = new Date(0);
33486 * d.setUTCMilliseconds(1234567890);
33487 *
33488 * A shared native helper to provide almost all setters. Magic value
33489 * contains a set of flags and also packs the "maxnargs" argument. The
33490 * helper provides:
33491 *
33492 * setMilliseconds()
33493 * setUTCMilliseconds()
33494 * setSeconds()
33495 * setUTCSeconds()
33496 * setMinutes()
33497 * setUTCMinutes()
33498 * setHours()
33499 * setUTCHours()
33500 * setDate()
33501 * setUTCDate()
33502 * setMonth()
33503 * setUTCMonth()
33504 * setFullYear()
33505 * setUTCFullYear()
33506 * setYear()
33507 *
33508 * Notes:
33509 *
33510 * - Date.prototype.setYear() (Section B addition): special year check
33511 * is omitted. NaN / Infinity will just flow through and ultimately
33512 * result in a NaN internal time value.
33513 *
33514 * - Date.prototype.setYear() does not have optional arguments for
33515 * setting month and day-in-month (like setFullYear()), but we indicate
33516 * 'maxnargs' to be 3 to get the year written to the correct component
33517 * index in duk__set_part_helper(). The function has nargs == 1, so only
33518 * the year will be set regardless of actual argument count.
33519 */
33520
33521DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) {
33522 duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr);
33523 return duk__set_part_helper(thr, flags_and_maxnargs);
33524}
33525
33526DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
33527 duk_double_t d;
33528
33529 (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */
33530 d = duk__timeclip(duk_to_number(thr, 0));
33531 duk_push_number(thr, d);
33532 duk_dup_top(thr);
33533 /* Must force write because .setTime() must work even when
33534 * the Date instance is frozen.
33535 */
33536 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
33537 /* -> [ timeval this timeval ] */
33538
33539 return 1;
33540}
33541
33542/*
33543 * Misc.
33544 */
33545
33546#if defined(DUK_USE_SYMBOL_BUILTIN)
33547DUK_INTERNAL duk_ret_t duk_bi_date_prototype_toprimitive(duk_hthread *thr) {
33548 duk_size_t hintlen;
33549 const char *hintstr;
33550 duk_int_t hint;
33551
33552 /* Invokes OrdinaryToPrimitive() with suitable hint. Note that the
33553 * method is generic, and works on non-Date arguments too.
33554 *
33555 * https://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@toprimitive
33556 */
33557
33558 duk_push_this(thr);
33559 duk_require_object(thr, -1);
33560 DUK_ASSERT_TOP(thr, 2);
33561
33562 hintstr = duk_require_lstring(thr, 0, &hintlen);
33563 if ((hintlen == 6 && DUK_STRCMP(hintstr, "string") == 0) ||
33564 (hintlen == 7 && DUK_STRCMP(hintstr, "default") == 0)) {
33565 hint = DUK_HINT_STRING;
33566 } else if (hintlen == 6 && DUK_STRCMP(hintstr, "number") == 0) {
33567 hint = DUK_HINT_NUMBER;
33568 } else {
33569 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
33570 }
33571
33572 duk_to_primitive_ordinary(thr, -1, hint);
33573 return 1;
33574}
33575#endif /* DUK_USE_SYMBOL_BUILTIN */
33576
33577#endif /* DUK_USE_DATE_BUILTIN */
33578
33579/* automatic undefs */
33580#undef DUK__CF_ACCEPT
33581#undef DUK__CF_ACCEPT_NUL
33582#undef DUK__CF_NEG
33583#undef DUK__DPRINT_DPARTS
33584#undef DUK__DPRINT_PARTS
33585#undef DUK__DPRINT_PARTS_AND_DPARTS
33586#undef DUK__LOCAL_TZOFFSET_MAXITER
33587#undef DUK__NUM_ISO8601_PARSER_PARTS
33588#undef DUK__PACK_RULE
33589#undef DUK__PI_DAY
33590#undef DUK__PI_HOUR
33591#undef DUK__PI_MILLISECOND
33592#undef DUK__PI_MINUTE
33593#undef DUK__PI_MONTH
33594#undef DUK__PI_SECOND
33595#undef DUK__PI_TZHOUR
33596#undef DUK__PI_TZMINUTE
33597#undef DUK__PI_YEAR
33598#undef DUK__PM_DAY
33599#undef DUK__PM_HOUR
33600#undef DUK__PM_MILLISECOND
33601#undef DUK__PM_MINUTE
33602#undef DUK__PM_MONTH
33603#undef DUK__PM_SECOND
33604#undef DUK__PM_TZHOUR
33605#undef DUK__PM_TZMINUTE
33606#undef DUK__PM_YEAR
33607#undef DUK__RULE_MASK_PART_SEP
33608#undef DUK__SI_COLON
33609#undef DUK__SI_MINUS
33610#undef DUK__SI_NUL
33611#undef DUK__SI_PERIOD
33612#undef DUK__SI_PLUS
33613#undef DUK__SI_SPACE
33614#undef DUK__SI_T
33615#undef DUK__SI_Z
33616#undef DUK__SM_COLON
33617#undef DUK__SM_MINUS
33618#undef DUK__SM_NUL
33619#undef DUK__SM_PERIOD
33620#undef DUK__SM_PLUS
33621#undef DUK__SM_SPACE
33622#undef DUK__SM_T
33623#undef DUK__SM_Z
33624#undef DUK__UNPACK_RULE
33625#undef DUK__WEEKDAY_MOD_ADDER
33626#undef DUK__YEAR
33627#line 1 "duk_bi_date_unix.c"
33628/*
33629 * Unix-like Date providers
33630 *
33631 * Generally useful Unix / POSIX / ANSI Date providers.
33632 */
33633
33634/* #include duk_internal.h -> already included */
33635
33636/* The necessary #includes are in place in duk_config.h. */
33637
33638/* Buffer sizes for some UNIX calls. Larger than strictly necessary
33639 * to avoid Valgrind errors.
33640 */
33641#define DUK__STRPTIME_BUF_SIZE 64
33642#define DUK__STRFTIME_BUF_SIZE 64
33643
33644#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
33645/* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */
33646DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
33647 struct timeval tv;
33648 duk_double_t d;
33649
33650 if (gettimeofday(&tv, NULL) != 0) {
33651 DUK_D(DUK_DPRINT("gettimeofday() failed"));
33652 return 0.0;
33653 }
33654
33655 /* As of Duktape 2.2.0 allow fractions. */
33656 d = ((duk_double_t) tv.tv_sec) * 1000.0 +
33657 ((duk_double_t) tv.tv_usec) / 1000.0;
33658
33659 return d;
33660}
33661#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
33662
33663#if defined(DUK_USE_DATE_NOW_TIME)
33664/* Not a very good provider: only full seconds are available. */
33665DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
33666 time_t t;
33667
33668 t = time(NULL);
33669 if (t == (time_t) -1) {
33670 DUK_D(DUK_DPRINT("time() failed"));
33671 return 0.0;
33672 }
33673 return ((duk_double_t) t) * 1000.0;
33674}
33675#endif /* DUK_USE_DATE_NOW_TIME */
33676
33677#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
33678/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
33679DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
33680 time_t t, t1, t2;
33681 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
33682 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
33683 struct tm tms[2];
33684#if defined(DUK_USE_DATE_TZO_GMTIME)
33685 struct tm *tm_ptr;
33686#endif
33687
33688 /* For NaN/inf, the return value doesn't matter. */
33689 if (!DUK_ISFINITE(d)) {
33690 return 0;
33691 }
33692
33693 /* If not within ECMAScript range, some integer time calculations
33694 * won't work correctly (and some asserts will fail), so bail out
33695 * if so. This fixes test-bug-date-insane-setyear.js. There is
33696 * a +/- 24h leeway in this range check to avoid a test262 corner
33697 * case documented in test-bug-date-timeval-edges.js.
33698 */
33699 if (!duk_bi_date_timeval_in_leeway_range(d)) {
33700 DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
33701 return 0;
33702 }
33703
33704 /*
33705 * This is a bit tricky to implement portably. The result depends
33706 * on the timestamp (specifically, DST depends on the timestamp).
33707 * If e.g. UNIX APIs are used, they'll have portability issues with
33708 * very small and very large years.
33709 *
33710 * Current approach:
33711 *
33712 * - Stay within portable UNIX limits by using equivalent year mapping.
33713 * Avoid year 1970 and 2038 as some conversions start to fail, at
33714 * least on some platforms. Avoiding 1970 means that there are
33715 * currently DST discrepancies for 1970.
33716 *
33717 * - Create a UTC and local time breakdowns from 't'. Then create
33718 * a time_t using gmtime() and localtime() and compute the time
33719 * difference between the two.
33720 *
33721 * Equivalent year mapping (E5 Section 15.9.1.8):
33722 *
33723 * If the host environment provides functionality for determining
33724 * daylight saving time, the implementation of ECMAScript is free
33725 * to map the year in question to an equivalent year (same
33726 * leap-year-ness and same starting week day for the year) for which
33727 * the host environment provides daylight saving time information.
33728 * The only restriction is that all equivalent years should produce
33729 * the same result.
33730 *
33731 * This approach is quite reasonable but not entirely correct, e.g.
33732 * the specification also states (E5 Section 15.9.1.8):
33733 *
33734 * The implementation of ECMAScript should not try to determine
33735 * whether the exact time was subject to daylight saving time, but
33736 * just whether daylight saving time would have been in effect if
33737 * the _current daylight saving time algorithm_ had been used at the
33738 * time. This avoids complications such as taking into account the
33739 * years that the locale observed daylight saving time year round.
33740 *
33741 * Since we rely on the platform APIs for conversions between local
33742 * time and UTC, we can't guarantee the above. Rather, if the platform
33743 * has historical DST rules they will be applied. This seems to be the
33744 * general preferred direction in ECMAScript standardization (or at least
33745 * implementations) anyway, and even the equivalent year mapping should
33746 * be disabled if the platform is known to handle DST properly for the
33747 * full ECMAScript range.
33748 *
33749 * The following has useful discussion and links:
33750 *
33751 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
33752 */
33753
33754 duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
33755 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
33756
33757 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
33758 DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
33759 t = (time_t) (d / 1000.0);
33760 DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
33761
33762 duk_memzero((void *) tms, sizeof(struct tm) * 2);
33763
33764#if defined(DUK_USE_DATE_TZO_GMTIME_R)
33765 (void) gmtime_r(&t, &tms[0]);
33766 (void) localtime_r(&t, &tms[1]);
33767#elif defined(DUK_USE_DATE_TZO_GMTIME_S)
33768 (void) gmtime_s(&t, &tms[0]);
33769 (void) localtime_s(&t, &tms[1]);
33770#elif defined(DUK_USE_DATE_TZO_GMTIME)
33771 tm_ptr = gmtime(&t);
33772 duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm));
33773 tm_ptr = localtime(&t);
33774 duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm));
33775#else
33776#error internal error
33777#endif
33778 DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
33779 "wday:%ld,yday:%ld,isdst:%ld}",
33780 (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
33781 (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
33782 (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
33783 DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
33784 "wday:%ld,yday:%ld,isdst:%ld}",
33785 (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
33786 (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
33787 (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
33788
33789 /* tm_isdst is both an input and an output to mktime(), use 0 to
33790 * avoid DST handling in mktime():
33791 * - https://github.com/svaarala/duktape/issues/406
33792 * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
33793 */
33794 tms[0].tm_isdst = 0;
33795 tms[1].tm_isdst = 0;
33796 t1 = mktime(&tms[0]); /* UTC */
33797 t2 = mktime(&tms[1]); /* local */
33798 if (t1 == (time_t) -1 || t2 == (time_t) -1) {
33799 /* This check used to be for (t < 0) but on some platforms
33800 * time_t is unsigned and apparently the proper way to detect
33801 * an mktime() error return is the cast above. See e.g.:
33802 * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
33803 */
33804 goto mktime_error;
33805 }
33806 DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
33807
33808 /* Compute final offset in seconds, positive if local time ahead of
33809 * UTC (returned value is UTC-to-local offset).
33810 *
33811 * difftime() returns a double, so coercion to int generates quite
33812 * a lot of code. Direct subtraction is not portable, however.
33813 * XXX: allow direct subtraction on known platforms.
33814 */
33815#if 0
33816 return (duk_int_t) (t2 - t1);
33817#endif
33818 return (duk_int_t) difftime(t2, t1);
33819
33820 mktime_error:
33821 /* XXX: return something more useful, so that caller can throw? */
33822 DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
33823 return 0;
33824}
33825#endif /* DUK_USE_DATE_TZO_GMTIME */
33826
33827#if defined(DUK_USE_DATE_PRS_STRPTIME)
33828DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
33829 struct tm tm;
33830 time_t t;
33831 char buf[DUK__STRPTIME_BUF_SIZE];
33832
33833 /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
33834 DUK_ASSERT(str != NULL);
33835 duk_memzero(buf, sizeof(buf)); /* valgrind whine without this */
33836 DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
33837 buf[sizeof(buf) - 1] = (char) 0;
33838
33839 DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
33840
33841 duk_memzero(&tm, sizeof(tm));
33842 if (strptime((const char *) buf, "%c", &tm) != NULL) {
33843 DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
33844 "wday:%ld,yday:%ld,isdst:%ld}",
33845 (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
33846 (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
33847 (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
33848 tm.tm_isdst = -1; /* negative: dst info not available */
33849
33850 t = mktime(&tm);
33851 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
33852 if (t >= 0) {
33853 duk_push_number(thr, ((duk_double_t) t) * 1000.0);
33854 return 1;
33855 }
33856 }
33857
33858 return 0;
33859}
33860#endif /* DUK_USE_DATE_PRS_STRPTIME */
33861
33862#if defined(DUK_USE_DATE_PRS_GETDATE)
33863DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
33864 struct tm tm;
33865 duk_small_int_t rc;
33866 time_t t;
33867
33868 /* For this to work, DATEMSK must be set, so this is not very
33869 * convenient for an embeddable interpreter.
33870 */
33871
33872 duk_memzero(&tm, sizeof(struct tm));
33873 rc = (duk_small_int_t) getdate_r(str, &tm);
33874 DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
33875
33876 if (rc == 0) {
33877 t = mktime(&tm);
33878 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
33879 if (t >= 0) {
33880 duk_push_number(thr, (duk_double_t) t);
33881 return 1;
33882 }
33883 }
33884
33885 return 0;
33886}
33887#endif /* DUK_USE_DATE_PRS_GETDATE */
33888
33889#if defined(DUK_USE_DATE_FMT_STRFTIME)
33890DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
33891 char buf[DUK__STRFTIME_BUF_SIZE];
33892 struct tm tm;
33893 const char *fmt;
33894
33895 DUK_UNREF(tzoffset);
33896
33897 /* If the platform doesn't support the entire ECMAScript range, we need
33898 * to return 0 so that the caller can fall back to the default formatter.
33899 *
33900 * For now, assume that if time_t is 8 bytes or more, the whole ECMAScript
33901 * range is supported. For smaller time_t values (4 bytes in practice),
33902 * assumes that the signed 32-bit range is supported.
33903 *
33904 * XXX: detect this more correctly per platform. The size of time_t is
33905 * probably not an accurate guarantee of strftime() supporting or not
33906 * supporting a large time range (the full ECMAScript range).
33907 */
33908 if (sizeof(time_t) < 8 &&
33909 (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
33910 /* be paranoid for 32-bit time values (even avoiding negative ones) */
33911 return 0;
33912 }
33913
33914 duk_memzero(&tm, sizeof(tm));
33915 tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
33916 tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
33917 tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
33918 tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
33919 tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
33920 tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
33921 tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
33922 tm.tm_isdst = 0;
33923
33924 duk_memzero(buf, sizeof(buf));
33925 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
33926 fmt = "%c";
33927 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
33928 fmt = "%x";
33929 } else {
33930 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
33931 fmt = "%X";
33932 }
33933 (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
33934 DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
33935
33936 duk_push_string(thr, buf);
33937 return 1;
33938}
33939#endif /* DUK_USE_DATE_FMT_STRFTIME */
33940
33941#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
33942DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
33943 struct timespec ts;
33944
33945 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
33946 return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
33947 } else {
33948 DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
33949 return 0.0;
33950 }
33951}
33952#endif
33953
33954/* automatic undefs */
33955#undef DUK__STRFTIME_BUF_SIZE
33956#undef DUK__STRPTIME_BUF_SIZE
33957#line 1 "duk_bi_date_windows.c"
33958/*
33959 * Windows Date providers
33960 *
33961 * Platform specific links:
33962 *
33963 * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
33964 */
33965
33966/* #include duk_internal.h -> already included */
33967
33968/* The necessary #includes are in place in duk_config.h. */
33969
33970#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
33971/* Shared Windows helpers. */
33972DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
33973 FILETIME ft;
33974 if (SystemTimeToFileTime(st, &ft) == 0) {
33975 DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
33976 res->QuadPart = 0;
33977 } else {
33978 res->LowPart = ft.dwLowDateTime;
33979 res->HighPart = ft.dwHighDateTime;
33980 }
33981}
33982
33983#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
33984DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
33985 res->LowPart = ft->dwLowDateTime;
33986 res->HighPart = ft->dwHighDateTime;
33987}
33988#endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */
33989
33990DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
33991 duk_memzero((void *) st, sizeof(*st));
33992 st->wYear = 1970;
33993 st->wMonth = 1;
33994 st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
33995 st->wDay = 1;
33996 DUK_ASSERT(st->wHour == 0);
33997 DUK_ASSERT(st->wMinute == 0);
33998 DUK_ASSERT(st->wSecond == 0);
33999 DUK_ASSERT(st->wMilliseconds == 0);
34000}
34001#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
34002
34003#if defined(DUK_USE_DATE_NOW_WINDOWS)
34004DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
34005 /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
34006 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
34007 */
34008 SYSTEMTIME st1, st2;
34009 ULARGE_INTEGER tmp1, tmp2;
34010
34011 GetSystemTime(&st1);
34012 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
34013
34014 duk__set_systime_jan1970(&st2);
34015 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
34016
34017 /* Difference is in 100ns units, convert to milliseconds, keeping
34018 * fractions since Duktape 2.2.0. This is only theoretical because
34019 * SYSTEMTIME is limited to milliseconds.
34020 */
34021 return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
34022}
34023#endif /* DUK_USE_DATE_NOW_WINDOWS */
34024
34025#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
34026DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
34027 /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
34028 * for more accuracy.
34029 */
34030 FILETIME ft1;
34031 SYSTEMTIME st2;
34032 ULARGE_INTEGER tmp1, tmp2;
34033
34034 GetSystemTimePreciseAsFileTime(&ft1);
34035 duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
34036
34037 duk__set_systime_jan1970(&st2);
34038 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
34039
34040 /* Difference is in 100ns units, convert to milliseconds, keeping
34041 * fractions since Duktape 2.2.0.
34042 */
34043 return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
34044}
34045#endif /* DUK_USE_DATE_NOW_WINDOWS */
34046
34047#if defined(DUK_USE_DATE_TZO_WINDOWS)
34048DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
34049 SYSTEMTIME st1;
34050 SYSTEMTIME st2;
34051 SYSTEMTIME st3;
34052 ULARGE_INTEGER tmp1;
34053 ULARGE_INTEGER tmp2;
34054 ULARGE_INTEGER tmp3;
34055 FILETIME ft1;
34056
34057 /* XXX: handling of timestamps outside Windows supported range.
34058 * How does Windows deal with dates before 1600? Does windows
34059 * support all ECMAScript years (like -200000 and +200000)?
34060 * Should equivalent year mapping be used here too? If so, use
34061 * a shared helper (currently integrated into timeval-to-parts).
34062 */
34063
34064 /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
34065 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
34066 */
34067
34068 duk__set_systime_jan1970(&st1);
34069 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
34070 tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
34071 tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
34072
34073 ft1.dwLowDateTime = tmp2.LowPart;
34074 ft1.dwHighDateTime = tmp2.HighPart;
34075 if (FileTimeToSystemTime((const FILETIME *) &ft1, &st2) == 0) {
34076 DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
34077 return 0;
34078 }
34079 if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
34080 DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
34081 return 0;
34082 }
34083 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
34084
34085 /* Positive if local time ahead of UTC. */
34086 return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
34087}
34088#endif /* DUK_USE_DATE_TZO_WINDOWS */
34089
34090#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
34091DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
34092 SYSTEMTIME st1;
34093 SYSTEMTIME st2;
34094 FILETIME ft1;
34095 FILETIME ft2;
34096 ULARGE_INTEGER tmp1;
34097 ULARGE_INTEGER tmp2;
34098
34099 /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
34100 * but without accounting for daylight savings time. Use this on
34101 * Windows platforms (like Durango) that don't support the
34102 * SystemTimeToTzSpecificLocalTime() call.
34103 */
34104
34105 /* current time not needed for this computation */
34106 DUK_UNREF(d);
34107
34108 duk__set_systime_jan1970(&st1);
34109 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
34110
34111 ft1.dwLowDateTime = tmp1.LowPart;
34112 ft1.dwHighDateTime = tmp1.HighPart;
34113 if (FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2) == 0) {
34114 DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0"));
34115 return 0;
34116 }
34117 if (FileTimeToSystemTime((const FILETIME *) &ft2, &st2) == 0) {
34118 DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
34119 return 0;
34120 }
34121 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
34122
34123 return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
34124}
34125#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
34126
34127#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
34128DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
34129 LARGE_INTEGER count, freq;
34130
34131 /* There are legacy issues with QueryPerformanceCounter():
34132 * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
34133 * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
34134 *
34135 * We avoid these by enabling QPC by default only for Vista or later.
34136 */
34137
34138 if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
34139 /* XXX: QueryPerformanceFrequency() can be cached */
34140 return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
34141 } else {
34142 /* MSDN: "On systems that run Windows XP or later, the function
34143 * will always succeed and will thus never return zero."
34144 * Provide minimal error path just in case user enables this
34145 * feature in pre-XP Windows.
34146 */
34147 return 0.0;
34148 }
34149}
34150#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
34151#line 1 "duk_bi_duktape.c"
34152/*
34153 * Duktape built-ins
34154 *
34155 * Size optimization note: it might seem that vararg multipurpose functions
34156 * like fin(), enc(), and dec() are not very size optimal, but using a single
34157 * user-visible ECMAScript function saves a lot of run-time footprint; each
34158 * Function instance takes >100 bytes. Using a shared native helper and a
34159 * 'magic' value won't save much if there are multiple Function instances
34160 * anyway.
34161 */
34162
34163/* #include duk_internal.h -> already included */
34164
34165#if defined(DUK_USE_DUKTAPE_BUILTIN)
34166
34167DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
34168 duk_inspect_value(thr, -1);
34169 return 1;
34170}
34171
34172DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
34173 duk_int_t level;
34174
34175 level = duk_to_int(thr, 0);
34176 duk_inspect_callstack_entry(thr, level);
34177 return 1;
34178}
34179
34180DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
34181 duk_small_uint_t flags;
34182
34183 flags = (duk_small_uint_t) duk_get_uint(thr, 0);
34184 duk_heap_mark_and_sweep(thr->heap, flags);
34185
34186 /* XXX: Not sure what the best return value would be in the API.
34187 * Return true for now.
34188 */
34189 duk_push_true(thr);
34190 return 1;
34191}
34192
34193#if defined(DUK_USE_FINALIZER_SUPPORT)
34194DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
34195 (void) duk_require_hobject(thr, 0);
34196 if (duk_get_top(thr) >= 2) {
34197 /* Set: currently a finalizer is disabled by setting it to
34198 * undefined; this does not remove the property at the moment.
34199 * The value could be type checked to be either a function
34200 * or something else; if something else, the property could
34201 * be deleted. Must use duk_set_finalizer() to keep
34202 * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
34203 */
34204 duk_set_top(thr, 2);
34205 duk_set_finalizer(thr, 0);
34206 return 0;
34207 } else {
34208 /* Get. */
34209 DUK_ASSERT(duk_get_top(thr) == 1);
34210 duk_get_finalizer(thr, 0);
34211 return 1;
34212 }
34213}
34214#endif /* DUK_USE_FINALIZER_SUPPORT */
34215
34216DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
34217 duk_hstring *h_str;
34218
34219 /* Vararg function: must be careful to check/require arguments.
34220 * The JSON helpers accept invalid indices and treat them like
34221 * non-existent optional parameters.
34222 */
34223
34224 h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */
34225 duk_require_valid_index(thr, 1);
34226
34227 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
34228 duk_set_top(thr, 2);
34229 duk_hex_encode(thr, 1);
34230 DUK_ASSERT_TOP(thr, 2);
34231 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
34232 duk_set_top(thr, 2);
34233 duk_base64_encode(thr, 1);
34234 DUK_ASSERT_TOP(thr, 2);
34235#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
34236 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
34237 duk_bi_json_stringify_helper(thr,
34238 1 /*idx_value*/,
34239 2 /*idx_replacer*/,
34240 3 /*idx_space*/,
34241 DUK_JSON_FLAG_EXT_CUSTOM |
34242 DUK_JSON_FLAG_ASCII_ONLY |
34243 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
34244#endif
34245#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
34246 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
34247 duk_bi_json_stringify_helper(thr,
34248 1 /*idx_value*/,
34249 2 /*idx_replacer*/,
34250 3 /*idx_space*/,
34251 DUK_JSON_FLAG_EXT_COMPATIBLE |
34252 DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
34253#endif
34254 } else {
34255 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
34256 }
34257 return 1;
34258}
34259
34260DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
34261 duk_hstring *h_str;
34262
34263 /* Vararg function: must be careful to check/require arguments.
34264 * The JSON helpers accept invalid indices and treat them like
34265 * non-existent optional parameters.
34266 */
34267
34268 h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */
34269 duk_require_valid_index(thr, 1);
34270
34271 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
34272 duk_set_top(thr, 2);
34273 duk_hex_decode(thr, 1);
34274 DUK_ASSERT_TOP(thr, 2);
34275 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
34276 duk_set_top(thr, 2);
34277 duk_base64_decode(thr, 1);
34278 DUK_ASSERT_TOP(thr, 2);
34279#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
34280 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
34281 duk_bi_json_parse_helper(thr,
34282 1 /*idx_value*/,
34283 2 /*idx_replacer*/,
34284 DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
34285#endif
34286#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
34287 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
34288 duk_bi_json_parse_helper(thr,
34289 1 /*idx_value*/,
34290 2 /*idx_replacer*/,
34291 DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
34292#endif
34293 } else {
34294 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
34295 }
34296 return 1;
34297}
34298
34299/*
34300 * Compact an object
34301 */
34302
34303DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
34304 DUK_ASSERT_TOP(thr, 1);
34305 duk_compact(thr, 0);
34306 return 1; /* return the argument object */
34307}
34308
34309#endif /* DUK_USE_DUKTAPE_BUILTIN */
34310#line 1 "duk_bi_encoding.c"
34311/*
34312 * WHATWG Encoding API built-ins
34313 *
34314 * API specification: https://encoding.spec.whatwg.org/#api
34315 * Web IDL: https://www.w3.org/TR/WebIDL/
34316 */
34317
34318/* #include duk_internal.h -> already included */
34319
34320/*
34321 * Data structures for encoding/decoding
34322 */
34323
34324typedef struct {
34325 duk_uint8_t *out; /* where to write next byte(s) */
34326 duk_codepoint_t lead; /* lead surrogate */
34327} duk__encode_context;
34328
34329typedef struct {
34330 /* UTF-8 decoding state */
34331 duk_codepoint_t codepoint; /* built up incrementally */
34332 duk_uint8_t upper; /* max value of next byte (decode error otherwise) */
34333 duk_uint8_t lower; /* min value of next byte (ditto) */
34334 duk_uint8_t needed; /* how many more bytes we need */
34335 duk_uint8_t bom_handled; /* BOM seen or no longer expected */
34336
34337 /* Decoder configuration */
34338 duk_uint8_t fatal;
34339 duk_uint8_t ignore_bom;
34340} duk__decode_context;
34341
34342/* The signed duk_codepoint_t type is used to signal a decoded codepoint
34343 * (>= 0) or various other states using negative values.
34344 */
34345#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */
34346#define DUK__CP_ERROR (-2) /* decoding error */
34347#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */
34348
34349/*
34350 * Raw helpers for encoding/decoding
34351 */
34352
34353/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
34354DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
34355 *ptr++ = 0xef;
34356 *ptr++ = 0xbf;
34357 *ptr++ = 0xbd;
34358 return ptr;
34359}
34360
34361DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
34362 /* (Re)init the decoding state of 'dec_ctx' but leave decoder
34363 * configuration fields untouched.
34364 */
34365 dec_ctx->codepoint = 0x0000L;
34366 dec_ctx->upper = 0xbf;
34367 dec_ctx->lower = 0x80;
34368 dec_ctx->needed = 0;
34369 dec_ctx->bom_handled = 0;
34370}
34371
34372DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
34373 /*
34374 * UTF-8 algorithm based on the Encoding specification:
34375 * https://encoding.spec.whatwg.org/#utf-8-decoder
34376 *
34377 * Two main states: decoding initial byte vs. decoding continuation
34378 * bytes. Shortest length encoding is validated by restricting the
34379 * allowed range of first continuation byte using 'lower' and 'upper'.
34380 */
34381
34382 if (dec_ctx->needed == 0) {
34383 /* process initial byte */
34384 if (x <= 0x7f) {
34385 /* U+0000-U+007F, 1 byte (ASCII) */
34386 return (duk_codepoint_t) x;
34387 } else if (x >= 0xc2 && x <= 0xdf) {
34388 /* U+0080-U+07FF, 2 bytes */
34389 dec_ctx->needed = 1;
34390 dec_ctx->codepoint = x & 0x1f;
34391 DUK_ASSERT(dec_ctx->lower == 0x80);
34392 DUK_ASSERT(dec_ctx->upper == 0xbf);
34393 return DUK__CP_CONTINUE;
34394 } else if (x >= 0xe0 && x <= 0xef) {
34395 /* U+0800-U+FFFF, 3 bytes */
34396 if (x == 0xe0) {
34397 dec_ctx->lower = 0xa0;
34398 DUK_ASSERT(dec_ctx->upper == 0xbf);
34399 } else if (x == 0xed) {
34400 DUK_ASSERT(dec_ctx->lower == 0x80);
34401 dec_ctx->upper = 0x9f;
34402 }
34403 dec_ctx->needed = 2;
34404 dec_ctx->codepoint = x & 0x0f;
34405 return DUK__CP_CONTINUE;
34406 } else if (x >= 0xf0 && x <= 0xf4) {
34407 /* U+010000-U+10FFFF, 4 bytes */
34408 if (x == 0xf0) {
34409 dec_ctx->lower = 0x90;
34410 DUK_ASSERT(dec_ctx->upper == 0xbf);
34411 } else if (x == 0xf4) {
34412 DUK_ASSERT(dec_ctx->lower == 0x80);
34413 dec_ctx->upper = 0x8f;
34414 }
34415 dec_ctx->needed = 3;
34416 dec_ctx->codepoint = x & 0x07;
34417 return DUK__CP_CONTINUE;
34418 } else {
34419 /* not a legal initial byte */
34420 return DUK__CP_ERROR;
34421 }
34422 } else {
34423 /* process continuation byte */
34424 if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
34425 dec_ctx->lower = 0x80;
34426 dec_ctx->upper = 0xbf;
34427 dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
34428 if (--dec_ctx->needed > 0) {
34429 /* need more bytes */
34430 return DUK__CP_CONTINUE;
34431 } else {
34432 /* got a codepoint */
34433 duk_codepoint_t ret;
34434 DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */
34435 ret = dec_ctx->codepoint;
34436 dec_ctx->codepoint = 0x0000L;
34437 dec_ctx->needed = 0;
34438 return ret;
34439 }
34440 } else {
34441 /* We just encountered an illegal UTF-8 continuation byte. This might
34442 * be the initial byte of the next character; if we return a plain
34443 * error status and the decoder is in replacement mode, the character
34444 * will be masked. We still need to alert the caller to the error
34445 * though.
34446 */
34447 dec_ctx->codepoint = 0x0000L;
34448 dec_ctx->needed = 0;
34449 dec_ctx->lower = 0x80;
34450 dec_ctx->upper = 0xbf;
34451 return DUK__CP_RETRY;
34452 }
34453 }
34454}
34455
34456#if defined(DUK_USE_ENCODING_BUILTINS)
34457DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
34458 duk__encode_context *enc_ctx;
34459
34460 DUK_ASSERT(codepoint >= 0);
34461 enc_ctx = (duk__encode_context *) udata;
34462 DUK_ASSERT(enc_ctx != NULL);
34463
34464#if !defined(DUK_USE_PREFER_SIZE)
34465 if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
34466 /* Fast path for ASCII. */
34467 *enc_ctx->out++ = (duk_uint8_t) codepoint;
34468 return;
34469 }
34470#endif
34471
34472 if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
34473 /* cannot legally encode in UTF-8 */
34474 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
34475 } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
34476 if (codepoint <= 0xdbffL) {
34477 /* high surrogate */
34478 duk_codepoint_t prev_lead = enc_ctx->lead;
34479 enc_ctx->lead = codepoint;
34480 if (prev_lead == 0x0000L) {
34481 /* high surrogate, no output */
34482 return;
34483 } else {
34484 /* consecutive high surrogates, consider first one unpaired */
34485 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
34486 }
34487 } else {
34488 /* low surrogate */
34489 if (enc_ctx->lead != 0x0000L) {
34490 codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
34491 enc_ctx->lead = 0x0000L;
34492 } else {
34493 /* unpaired low surrogate */
34494 DUK_ASSERT(enc_ctx->lead == 0x0000L);
34495 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
34496 }
34497 }
34498 } else {
34499 if (enc_ctx->lead != 0x0000L) {
34500 /* unpaired high surrogate: emit replacement character and the input codepoint */
34501 enc_ctx->lead = 0x0000L;
34502 enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
34503 }
34504 }
34505
34506 /* Codepoint may be original input, a decoded surrogate pair, or may
34507 * have been replaced with U+FFFD.
34508 */
34509 enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
34510}
34511#endif /* DUK_USE_ENCODING_BUILTINS */
34512
34513/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
34514 * decoder.
34515 */
34516DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
34517 const duk_uint8_t *input;
34518 duk_size_t len = 0;
34519 duk_size_t len_tmp;
34520 duk_bool_t stream = 0;
34521 duk_codepoint_t codepoint;
34522 duk_uint8_t *output;
34523 const duk_uint8_t *in;
34524 duk_uint8_t *out;
34525
34526 DUK_ASSERT(dec_ctx != NULL);
34527
34528 /* Careful with input buffer pointer: any side effects involving
34529 * code execution (e.g. getters, coercion calls, and finalizers)
34530 * may cause a resize and invalidate a pointer we've read. This
34531 * is why the pointer is actually looked up at the last minute.
34532 * Argument validation must still happen first to match WHATWG
34533 * required side effect order.
34534 */
34535
34536 if (duk_is_undefined(thr, 0)) {
34537 duk_push_fixed_buffer_nozero(thr, 0);
34538 duk_replace(thr, 0);
34539 }
34540 (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */
34541
34542 if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
34543 DUK_TYPE_MASK_NULL |
34544 DUK_TYPE_MASK_NONE)) {
34545 /* Use defaults, treat missing value like undefined. */
34546 } else {
34547 duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
34548 DUK_TYPE_MASK_NULL |
34549 DUK_TYPE_MASK_LIGHTFUNC |
34550 DUK_TYPE_MASK_BUFFER |
34551 DUK_TYPE_MASK_OBJECT);
34552 if (duk_get_prop_literal(thr, 1, "stream")) {
34553 stream = duk_to_boolean(thr, -1);
34554 }
34555 }
34556
34557 /* Allowance is 3*len in the general case because all bytes may potentially
34558 * become U+FFFD. If the first byte completes a non-BMP codepoint it will
34559 * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
34560 * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because
34561 * the 4->6 expansion is well under the 3x allowance.
34562 *
34563 * XXX: As with TextEncoder, need a better buffer allocation strategy here.
34564 */
34565 if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
34566 DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
34567 DUK_WO_NORETURN(return 0;);
34568 }
34569 output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
34570
34571 input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
34572 DUK_ASSERT(input != NULL || len == 0);
34573 if (DUK_UNLIKELY(len != len_tmp)) {
34574 /* Very unlikely but possible: source buffer was resized by
34575 * a side effect when fixed buffer was pushed. Output buffer
34576 * may not be large enough to hold output, so just fail if
34577 * length has changed.
34578 */
34579 DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
34580 goto fail_type;
34581 }
34582
34583 /* From this point onwards it's critical that no side effect occur
34584 * which may disturb 'input': finalizer execution, property accesses,
34585 * active coercions, etc. Even an allocation related mark-and-sweep
34586 * may affect the pointer because it may trigger a pending finalizer.
34587 */
34588
34589 in = input;
34590 out = output;
34591 while (in < input + len) {
34592 codepoint = duk__utf8_decode_next(dec_ctx, *in++);
34593 if (codepoint < 0) {
34594 if (codepoint == DUK__CP_CONTINUE) {
34595 continue;
34596 }
34597
34598 /* Decoding error with or without retry. */
34599 DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
34600 if (codepoint == DUK__CP_RETRY) {
34601 --in; /* retry last byte */
34602 }
34603 /* replacement mode: replace with U+FFFD */
34604 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
34605 if (dec_ctx->fatal) {
34606 /* fatal mode: throw a TypeError */
34607 goto fail_type;
34608 }
34609 /* Continue with 'codepoint', Unicode replacement. */
34610 }
34611 DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
34612
34613 if (!dec_ctx->bom_handled) {
34614 dec_ctx->bom_handled = 1;
34615 if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
34616 continue;
34617 }
34618 }
34619
34620 out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
34621 DUK_ASSERT(out <= output + (3 + (3 * len)));
34622 }
34623
34624 if (!stream) {
34625 if (dec_ctx->needed != 0) {
34626 /* truncated sequence at end of buffer */
34627 if (dec_ctx->fatal) {
34628 goto fail_type;
34629 } else {
34630 out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
34631 DUK_ASSERT(out <= output + (3 + (3 * len)));
34632 }
34633 }
34634 duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */
34635 }
34636
34637 /* Output buffer is fixed and thus stable even if there had been
34638 * side effects (which there shouldn't be).
34639 */
34640 duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
34641 return 1;
34642
34643 fail_type:
34644 DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
34645 DUK_WO_NORETURN(return 0;);
34646}
34647
34648/*
34649 * Built-in bindings
34650 */
34651
34652#if defined(DUK_USE_ENCODING_BUILTINS)
34653DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
34654 /* TextEncoder currently requires no persistent state, so the constructor
34655 * does nothing on purpose.
34656 */
34657
34658 duk_require_constructor_call(thr);
34659 return 0;
34660}
34661
34662DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
34663 duk_push_literal(thr, "utf-8");
34664 return 1;
34665}
34666
34667DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
34668 duk__encode_context enc_ctx;
34669 duk_size_t len;
34670 duk_size_t final_len;
34671 duk_uint8_t *output;
34672
34673 DUK_ASSERT_TOP(thr, 1);
34674 if (duk_is_undefined(thr, 0)) {
34675 len = 0;
34676 } else {
34677 duk_hstring *h_input;
34678
34679 h_input = duk_to_hstring(thr, 0);
34680 DUK_ASSERT(h_input != NULL);
34681
34682 len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
34683 if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
34684 DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
34685 DUK_WO_NORETURN(return 0;);
34686 }
34687 }
34688
34689 /* Allowance is 3*len because all bytes can potentially be replaced with
34690 * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
34691 * Rely on dynamic buffer data pointer stability: no other code has
34692 * access to the data pointer.
34693 *
34694 * XXX: The buffer allocation strategy used here is rather inefficient.
34695 * Maybe switch to a chunk-based strategy, or preprocess the string to
34696 * figure out the space needed ahead of time?
34697 */
34698 DUK_ASSERT(3 * len >= len);
34699 output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
34700
34701 if (len > 0) {
34702 DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
34703
34704 /* XXX: duk_decode_string() is used to process the input
34705 * string. For standard ECMAScript strings, represented
34706 * internally as CESU-8, this is fine. However, behavior
34707 * beyond CESU-8 is not very strict: codepoints using an
34708 * extended form of UTF-8 are also accepted, and invalid
34709 * codepoint sequences (which are allowed in Duktape strings)
34710 * are not handled as well as they could (e.g. invalid
34711 * continuation bytes may mask following codepoints).
34712 * This is how ECMAScript code would also see such strings.
34713 * Maybe replace duk_decode_string() with an explicit strict
34714 * CESU-8 decoder here?
34715 */
34716 enc_ctx.lead = 0x0000L;
34717 enc_ctx.out = output;
34718 duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
34719 if (enc_ctx.lead != 0x0000L) {
34720 /* unpaired high surrogate at end of string */
34721 enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
34722 DUK_ASSERT(enc_ctx.out <= output + (3 * len));
34723 }
34724
34725 /* The output buffer is usually very much oversized, so shrink it to
34726 * actually needed size. Pointer stability assumed up to this point.
34727 */
34728 DUK_ASSERT_TOP(thr, 2);
34729 DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
34730
34731 final_len = (duk_size_t) (enc_ctx.out - output);
34732 duk_resize_buffer(thr, -1, final_len);
34733 /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
34734 } else {
34735 final_len = 0;
34736 }
34737
34738 /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
34739 * be backed by a dynamic buffer which differs from e.g. Uint8Arrays
34740 * created as 'new Uint8Array(N)'. ECMAScript code won't see the
34741 * difference but C code will. When bufferobjects are not supported,
34742 * returns a plain dynamic buffer.
34743 */
34744#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
34745 duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
34746#endif
34747 return 1;
34748}
34749
34750DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
34751 duk__decode_context *dec_ctx;
34752 duk_bool_t fatal = 0;
34753 duk_bool_t ignore_bom = 0;
34754
34755 DUK_ASSERT_TOP(thr, 2);
34756 duk_require_constructor_call(thr);
34757 if (!duk_is_undefined(thr, 0)) {
34758 /* XXX: For now ignore 'label' (encoding identifier). */
34759 duk_to_string(thr, 0);
34760 }
34761 if (!duk_is_null_or_undefined(thr, 1)) {
34762 if (duk_get_prop_literal(thr, 1, "fatal")) {
34763 fatal = duk_to_boolean(thr, -1);
34764 }
34765 if (duk_get_prop_literal(thr, 1, "ignoreBOM")) {
34766 ignore_bom = duk_to_boolean(thr, -1);
34767 }
34768 }
34769
34770 duk_push_this(thr);
34771
34772 /* The decode context is not assumed to be zeroed; all fields are
34773 * initialized explicitly.
34774 */
34775 dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
34776 dec_ctx->fatal = (duk_uint8_t) fatal;
34777 dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
34778 duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
34779
34780 duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
34781 return 0;
34782}
34783
34784/* Get TextDecoder context from 'this'; leaves garbage on stack. */
34785DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
34786 duk__decode_context *dec_ctx;
34787 duk_push_this(thr);
34788 duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
34789 dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
34790 DUK_ASSERT(dec_ctx != NULL);
34791 return dec_ctx;
34792}
34793
34794DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
34795 duk__decode_context *dec_ctx;
34796 duk_int_t magic;
34797
34798 dec_ctx = duk__get_textdecoder_context(thr);
34799 magic = duk_get_current_magic(thr);
34800 switch (magic) {
34801 case 0:
34802 /* Encoding is now fixed, so _Context lookup is only needed to
34803 * validate the 'this' binding (TypeError if not TextDecoder-like).
34804 */
34805 duk_push_literal(thr, "utf-8");
34806 break;
34807 case 1:
34808 duk_push_boolean(thr, dec_ctx->fatal);
34809 break;
34810 default:
34811 duk_push_boolean(thr, dec_ctx->ignore_bom);
34812 break;
34813 }
34814
34815 return 1;
34816}
34817
34818DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
34819 duk__decode_context *dec_ctx;
34820
34821 dec_ctx = duk__get_textdecoder_context(thr);
34822 return duk__decode_helper(thr, dec_ctx);
34823}
34824#endif /* DUK_USE_ENCODING_BUILTINS */
34825
34826/*
34827 * Internal helper for Node.js Buffer
34828 */
34829
34830/* Internal helper used for Node.js Buffer .toString(). Value stack convention
34831 * is currently odd: it mimics TextDecoder .decode() so that argument must be at
34832 * index 0, and decode options (not present for Buffer) at index 1. Return value
34833 * is a Duktape/C function return value.
34834 */
34835DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
34836 duk__decode_context dec_ctx;
34837
34838 dec_ctx.fatal = 0; /* use replacement chars */
34839 dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
34840 duk__utf8_decode_init(&dec_ctx);
34841
34842 return duk__decode_helper(thr, &dec_ctx);
34843}
34844
34845/* automatic undefs */
34846#undef DUK__CP_CONTINUE
34847#undef DUK__CP_ERROR
34848#undef DUK__CP_RETRY
34849#line 1 "duk_bi_error.c"
34850/*
34851 * Error built-ins
34852 */
34853
34854/* #include duk_internal.h -> already included */
34855
34856DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
34857 /* Behavior for constructor and non-constructor call is
34858 * the same except for augmenting the created error. When
34859 * called as a constructor, the caller (duk_new()) will handle
34860 * augmentation; when called as normal function, we need to do
34861 * it here.
34862 */
34863
34864 duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
34865
34866 /* same for both error and each subclass like TypeError */
34867 duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
34868 DUK_HOBJECT_FLAG_FASTREFS |
34869 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
34870
34871 (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
34872
34873 /* If message is undefined, the own property 'message' is not set at
34874 * all to save property space. An empty message is inherited anyway.
34875 */
34876 if (!duk_is_undefined(thr, 0)) {
34877 duk_to_string(thr, 0);
34878 duk_dup_0(thr); /* [ message error message ] */
34879 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
34880 }
34881
34882 /* Augment the error if called as a normal function. __FILE__ and __LINE__
34883 * are not desirable in this case.
34884 */
34885
34886#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
34887 if (!duk_is_constructor_call(thr)) {
34888 duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
34889 }
34890#endif
34891
34892 return 1;
34893}
34894
34895DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
34896 /* XXX: optimize with more direct internal access */
34897
34898 duk_push_this(thr);
34899 (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
34900
34901 /* [ ... this ] */
34902
34903 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
34904 if (duk_is_undefined(thr, -1)) {
34905 duk_pop(thr);
34906 duk_push_literal(thr, "Error");
34907 } else {
34908 duk_to_string(thr, -1);
34909 }
34910
34911 /* [ ... this name ] */
34912
34913 /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
34914 * accident or are they actually needed? The first ToString()
34915 * could conceivably return 'undefined'.
34916 */
34917 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
34918 if (duk_is_undefined(thr, -1)) {
34919 duk_pop(thr);
34920 duk_push_hstring_empty(thr);
34921 } else {
34922 duk_to_string(thr, -1);
34923 }
34924
34925 /* [ ... this name message ] */
34926
34927 if (duk_get_length(thr, -2) == 0) {
34928 /* name is empty -> return message */
34929 return 1;
34930 }
34931 if (duk_get_length(thr, -1) == 0) {
34932 /* message is empty -> return name */
34933 duk_pop(thr);
34934 return 1;
34935 }
34936 duk_push_literal(thr, ": ");
34937 duk_insert(thr, -2); /* ... name ': ' message */
34938 duk_concat(thr, 3);
34939
34940 return 1;
34941}
34942
34943#if defined(DUK_USE_TRACEBACKS)
34944
34945/*
34946 * Traceback handling
34947 *
34948 * The unified helper decodes the traceback and produces various requested
34949 * outputs. It should be optimized for size, and may leave garbage on stack,
34950 * only the topmost return value matters. For instance, traceback separator
34951 * and decoded strings are pushed even when looking for filename only.
34952 *
34953 * NOTE: although _Tracedata is an internal property, user code can currently
34954 * write to the array (or replace it with something other than an array).
34955 * The code below must tolerate arbitrary _Tracedata. It can throw errors
34956 * etc, but cannot cause a segfault or memory unsafe behavior.
34957 */
34958
34959/* constants arbitrary, chosen for small loads */
34960#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
34961#define DUK__OUTPUT_TYPE_FILENAME 0
34962#define DUK__OUTPUT_TYPE_LINENUMBER 1
34963
34964DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
34965 duk_idx_t idx_td;
34966 duk_small_int_t i; /* traceback depth fits into 16 bits */
34967 duk_small_int_t t; /* stack type fits into 16 bits */
34968 duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
34969 const char *str_tailcall = " tailcall";
34970 const char *str_strict = " strict";
34971 const char *str_construct = " construct";
34972 const char *str_prevyield = " preventsyield";
34973 const char *str_directeval = " directeval";
34974 const char *str_empty = "";
34975
34976 DUK_ASSERT_TOP(thr, 0); /* fixed arg count */
34977
34978 duk_push_this(thr);
34979 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
34980 idx_td = duk_get_top_index(thr);
34981
34982 duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
34983 duk_push_this(thr);
34984
34985 /* [ ... this tracedata sep this ] */
34986
34987 /* XXX: skip null filename? */
34988
34989 if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
34990 /* Current tracedata contains 2 entries per callstack entry. */
34991 for (i = 0; ; i += 2) {
34992 duk_int_t pc;
34993 duk_uint_t line;
34994 duk_uint_t flags;
34995 duk_double_t d;
34996 const char *funcname;
34997 const char *filename;
34998 duk_hobject *h_func;
34999 duk_hstring *h_name;
35000
35001 duk_require_stack(thr, 5);
35002 duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
35003 duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
35004 d = duk_to_number_m1(thr);
35005 pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32));
35006 flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32));
35007 t = (duk_small_int_t) duk_get_type(thr, -2);
35008
35009 if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
35010 /*
35011 * ECMAScript/native function call or lightfunc call
35012 */
35013
35014 count_func++;
35015
35016 /* [ ... v1(func) v2(pc+flags) ] */
35017
35018 /* These may be systematically omitted by Duktape
35019 * with certain config options, but allow user to
35020 * set them on a case-by-case basis.
35021 */
35022 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
35023 duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
35024
35025#if defined(DUK_USE_PC2LINE)
35026 line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
35027#else
35028 line = 0;
35029#endif
35030
35031 /* [ ... v1 v2 name filename ] */
35032
35033 /* When looking for .fileName/.lineNumber, blame first
35034 * function which has a .fileName.
35035 */
35036 if (duk_is_string_notsymbol(thr, -1)) {
35037 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
35038 return 1;
35039 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
35040 duk_push_uint(thr, line);
35041 return 1;
35042 }
35043 }
35044
35045 /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
35046 /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
35047 h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */
35048 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
35049 "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
35050 filename = duk_get_string_notsymbol(thr, -1);
35051 filename = filename ? filename : "";
35052 DUK_ASSERT(funcname != NULL);
35053 DUK_ASSERT(filename != NULL);
35054
35055 h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */
35056
35057 if (h_func == NULL) {
35058 duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
35059 (const char *) funcname,
35060 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
35061 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
35062 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
35063 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
35064 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
35065 } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
35066 duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
35067 (const char *) funcname,
35068 (const char *) filename,
35069 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
35070 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
35071 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
35072 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
35073 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
35074 } else {
35075 duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
35076 (const char *) funcname,
35077 (const char *) filename,
35078 (unsigned long) line,
35079 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
35080 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
35081 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
35082 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
35083 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
35084 }
35085 duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
35086 duk_pop_3(thr); /* -> [ ... str ] */
35087 } else if (t == DUK_TYPE_STRING) {
35088 const char *str_file;
35089
35090 /*
35091 * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
35092 * Sometimes __FILE__ / __LINE__ is reported as the source for
35093 * the error (fileName, lineNumber), sometimes not.
35094 */
35095
35096 /* [ ... v1(filename) v2(line+flags) ] */
35097
35098 /* When looking for .fileName/.lineNumber, blame compilation
35099 * or C call site unless flagged not to do so.
35100 */
35101 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
35102 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
35103 duk_pop(thr);
35104 return 1;
35105 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
35106 duk_push_int(thr, pc);
35107 return 1;
35108 }
35109 }
35110
35111 /* Tracedata is trusted but avoid any risk of using a NULL
35112 * for %s format because it has undefined behavior. Symbols
35113 * don't need to be explicitly rejected as they pose no memory
35114 * safety issues.
35115 */
35116 str_file = (const char *) duk_get_string(thr, -2);
35117 duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
35118 (const char *) (str_file ? str_file : "null"), (long) pc);
35119 duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
35120 duk_pop(thr); /* -> [ ... str ] */
35121 } else {
35122 /* unknown, ignore */
35123 duk_pop_2(thr);
35124 break;
35125 }
35126 }
35127
35128 if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
35129 /* Possibly truncated; there is no explicit truncation
35130 * marker so this is the best we can do.
35131 */
35132
35133 duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
35134 }
35135 }
35136
35137 /* [ ... this tracedata sep this str1 ... strN ] */
35138
35139 if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
35140 return 0;
35141 } else {
35142 /* The 'this' after 'sep' will get ToString() coerced by
35143 * duk_join() automatically. We don't want to do that
35144 * coercion when providing .fileName or .lineNumber (GH-254).
35145 */
35146 duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
35147 return 1;
35148 }
35149}
35150
35151/* XXX: Output type could be encoded into native function 'magic' value to
35152 * save space. For setters the stridx could be encoded into 'magic'.
35153 */
35154
35155DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
35156 return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
35157}
35158
35159DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
35160 return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
35161}
35162
35163DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
35164 return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
35165}
35166
35167#else /* DUK_USE_TRACEBACKS */
35168
35169/*
35170 * Traceback handling when tracebacks disabled.
35171 *
35172 * The fileName / lineNumber stubs are now necessary because built-in
35173 * data will include the accessor properties in Error.prototype. If those
35174 * are removed for builds without tracebacks, these can also be removed.
35175 * 'stack' should still be present and produce a ToString() equivalent:
35176 * this is useful for user code which prints a stacktrace and expects to
35177 * see something useful. A normal stacktrace also begins with a ToString()
35178 * of the error so this makes sense.
35179 */
35180
35181DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
35182 /* XXX: remove this native function and map 'stack' accessor
35183 * to the toString() implementation directly.
35184 */
35185 return duk_bi_error_prototype_to_string(thr);
35186}
35187
35188DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
35189 DUK_UNREF(thr);
35190 return 0;
35191}
35192
35193DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
35194 DUK_UNREF(thr);
35195 return 0;
35196}
35197
35198#endif /* DUK_USE_TRACEBACKS */
35199
35200DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) {
35201 /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
35202 * user code called Object.defineProperty() to create an overriding
35203 * own property. This allows user code to overwrite .fileName etc
35204 * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
35205 * See https://github.com/svaarala/duktape/issues/387.
35206 */
35207
35208 DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */
35209
35210 duk_push_this(thr);
35211 duk_push_hstring_stridx(thr, stridx_key);
35212 duk_dup_0(thr);
35213
35214 /* [ ... obj key value ] */
35215
35216 DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
35217 duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
35218
35219 duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE |
35220 DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
35221 DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
35222 DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
35223 return 0;
35224}
35225
35226DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) {
35227 return duk__error_setter_helper(thr, DUK_STRIDX_STACK);
35228}
35229
35230DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) {
35231 return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME);
35232}
35233
35234DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
35235 return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
35236}
35237
35238/* automatic undefs */
35239#undef DUK__OUTPUT_TYPE_FILENAME
35240#undef DUK__OUTPUT_TYPE_LINENUMBER
35241#undef DUK__OUTPUT_TYPE_TRACEBACK
35242#line 1 "duk_bi_function.c"
35243/*
35244 * Function built-ins
35245 */
35246
35247/* #include duk_internal.h -> already included */
35248
35249/* Needed even when Function built-in is disabled. */
35250DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
35251 /* ignore arguments, return undefined (E5 Section 15.3.4) */
35252 DUK_UNREF(thr);
35253 return 0;
35254}
35255
35256#if defined(DUK_USE_FUNCTION_BUILTIN)
35257DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
35258 duk_hstring *h_sourcecode;
35259 duk_idx_t nargs;
35260 duk_idx_t i;
35261 duk_small_uint_t comp_flags;
35262 duk_hcompfunc *func;
35263 duk_hobject *outer_lex_env;
35264 duk_hobject *outer_var_env;
35265
35266 /* normal and constructor calls have identical semantics */
35267
35268 nargs = duk_get_top(thr);
35269 for (i = 0; i < nargs; i++) {
35270 duk_to_string(thr, i); /* Rejects Symbols during coercion. */
35271 }
35272
35273 if (nargs == 0) {
35274 duk_push_hstring_empty(thr);
35275 duk_push_hstring_empty(thr);
35276 } else if (nargs == 1) {
35277 /* XXX: cover this with the generic >1 case? */
35278 duk_push_hstring_empty(thr);
35279 } else {
35280 duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
35281 duk_push_literal(thr, ",");
35282 duk_insert(thr, 1);
35283 duk_join(thr, nargs - 1);
35284 }
35285
35286 /* [ body formals ], formals is comma separated list that needs to be parsed */
35287
35288 DUK_ASSERT_TOP(thr, 2);
35289
35290 /* XXX: this placeholder is not always correct, but use for now.
35291 * It will fail in corner cases; see test-dev-func-cons-args.js.
35292 */
35293 duk_push_literal(thr, "function(");
35294 duk_dup_1(thr);
35295 duk_push_literal(thr, "){");
35296 duk_dup_0(thr);
35297 duk_push_literal(thr, "\n}"); /* Newline is important to handle trailing // comment. */
35298 duk_concat(thr, 5);
35299
35300 /* [ body formals source ] */
35301
35302 DUK_ASSERT_TOP(thr, 3);
35303
35304 /* strictness is not inherited, intentional */
35305 comp_flags = DUK_COMPILE_FUNCEXPR;
35306
35307 duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
35308 h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */
35309 duk_js_compile(thr,
35310 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
35311 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
35312 comp_flags);
35313
35314 /* Force .name to 'anonymous' (ES2015). */
35315 duk_push_literal(thr, "anonymous");
35316 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
35317
35318 func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
35319 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
35320 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
35321
35322 /* [ body formals source template ] */
35323
35324 /* only outer_lex_env matters, as functions always get a new
35325 * variable declaration environment.
35326 */
35327
35328 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
35329 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
35330
35331 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
35332
35333 /* [ body formals source template closure ] */
35334
35335 return 1;
35336}
35337#endif /* DUK_USE_FUNCTION_BUILTIN */
35338
35339#if defined(DUK_USE_FUNCTION_BUILTIN)
35340DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
35341 duk_tval *tv;
35342
35343 /*
35344 * E5 Section 15.3.4.2 places few requirements on the output of
35345 * this function: the result is implementation dependent, must
35346 * follow FunctionDeclaration syntax (in particular, must have a
35347 * name even for anonymous functions or functions with empty name).
35348 * The output does NOT need to compile into anything useful.
35349 *
35350 * E6 Section 19.2.3.5 changes the requirements completely: the
35351 * result must either eval() to a functionally equivalent object
35352 * OR eval() to a SyntaxError.
35353 *
35354 * We opt for the SyntaxError approach for now, with a syntax that
35355 * mimics V8's native function syntax:
35356 *
35357 * 'function cos() { [native code] }'
35358 *
35359 * but extended with [ecmascript code], [bound code], and
35360 * [lightfunc code].
35361 */
35362
35363 duk_push_this(thr);
35364 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
35365 DUK_ASSERT(tv != NULL);
35366
35367 if (DUK_TVAL_IS_OBJECT(tv)) {
35368 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
35369 const char *func_name;
35370
35371 /* Function name: missing/undefined is mapped to empty string,
35372 * otherwise coerce to string. No handling for invalid identifier
35373 * characters or e.g. '{' in the function name. This doesn't
35374 * really matter as long as a SyntaxError results. Technically
35375 * if the name contained a suitable prefix followed by '//' it
35376 * might cause the result to parse without error.
35377 */
35378 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
35379 if (duk_is_undefined(thr, -1)) {
35380 func_name = "";
35381 } else {
35382 func_name = duk_to_string(thr, -1);
35383 DUK_ASSERT(func_name != NULL);
35384 }
35385
35386 if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
35387 duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
35388 } else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
35389 duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
35390 } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
35391 duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
35392 } else {
35393 goto type_error;
35394 }
35395 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
35396 duk_push_lightfunc_tostring(thr, tv);
35397 } else {
35398 goto type_error;
35399 }
35400
35401 return 1;
35402
35403 type_error:
35404 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
35405}
35406#endif
35407
35408/* Always present because the native function pointer is needed in call
35409 * handling.
35410 */
35411DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
35412 /* .call() is dealt with in call handling by simulating its
35413 * effects so this function is actually never called.
35414 */
35415 DUK_UNREF(thr);
35416 return DUK_RET_TYPE_ERROR;
35417}
35418
35419DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
35420 /* Like .call(), never actually called. */
35421 DUK_UNREF(thr);
35422 return DUK_RET_TYPE_ERROR;
35423}
35424
35425DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
35426 /* Like .call(), never actually called. */
35427 DUK_UNREF(thr);
35428 return DUK_RET_TYPE_ERROR;
35429}
35430
35431DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
35432 /* Like .call(), never actually called. */
35433 DUK_UNREF(thr);
35434 return DUK_RET_TYPE_ERROR;
35435}
35436
35437#if defined(DUK_USE_FUNCTION_BUILTIN)
35438/* Create a bound function which points to a target function which may
35439 * be bound or non-bound. If the target is bound, the argument lists
35440 * and 'this' binding of the functions are merged and the resulting
35441 * function points directly to the non-bound target.
35442 */
35443DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
35444 duk_hboundfunc *h_bound;
35445 duk_idx_t nargs; /* bound args, not counting 'this' binding */
35446 duk_idx_t bound_nargs;
35447 duk_int_t bound_len;
35448 duk_tval *tv_prevbound;
35449 duk_idx_t n_prevbound;
35450 duk_tval *tv_res;
35451 duk_tval *tv_tmp;
35452
35453 /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
35454
35455 /* Vararg function, careful arg handling, e.g. thisArg may not
35456 * be present.
35457 */
35458 nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */
35459 if (nargs < 0) {
35460 nargs++;
35461 duk_push_undefined(thr);
35462 }
35463 DUK_ASSERT(nargs >= 0);
35464
35465 /* Limit 'nargs' for bound functions to guarantee arithmetic
35466 * below will never wrap.
35467 */
35468 if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
35469 DUK_DCERROR_RANGE_INVALID_COUNT(thr);
35470 }
35471
35472 duk_push_this(thr);
35473 duk_require_callable(thr, -1);
35474
35475 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */
35476 DUK_ASSERT_TOP(thr, nargs + 2);
35477
35478 /* Create bound function object. */
35479 h_bound = duk_push_hboundfunc(thr);
35480 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
35481 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
35482 DUK_ASSERT(h_bound->args == NULL);
35483 DUK_ASSERT(h_bound->nargs == 0);
35484 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
35485
35486 /* [ thisArg arg1 ... argN func boundFunc ] */
35487
35488 /* If the target is a bound function, argument lists must be
35489 * merged. The 'this' binding closest to the target function
35490 * wins because in call handling the 'this' gets replaced over
35491 * and over again until we call the non-bound function.
35492 */
35493 tv_prevbound = NULL;
35494 n_prevbound = 0;
35495 tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
35496 DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
35497 tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
35498 DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
35499
35500 if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
35501 duk_hobject *h_target;
35502 duk_hobject *bound_proto;
35503
35504 h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
35505 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
35506
35507 /* Internal prototype must be copied from the target.
35508 * For lightfuncs Function.prototype is used and is already
35509 * in place.
35510 */
35511 bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
35512 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
35513
35514 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
35515 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
35516 * function. Not sure if this is correct, because the specification
35517 * is a bit ambiguous on this point but it would make sense.
35518 */
35519 /* Strictness is inherited from target. */
35520 if (DUK_HOBJECT_HAS_STRICT(h_target)) {
35521 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
35522 }
35523
35524 if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
35525 duk_hboundfunc *h_boundtarget;
35526
35527 h_boundtarget = (duk_hboundfunc *) (void *) h_target;
35528
35529 /* The final function should always be non-bound, unless
35530 * there's a bug in the internals. Assert for it.
35531 */
35532 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
35533 (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
35534 DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
35535 !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
35536
35537 DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
35538 DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
35539
35540 tv_prevbound = h_boundtarget->args;
35541 n_prevbound = h_boundtarget->nargs;
35542 }
35543 } else {
35544 /* Lightfuncs are always strict. */
35545 duk_hobject *bound_proto;
35546
35547 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
35548 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
35549 bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
35550 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
35551 }
35552
35553 DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */
35554 DUK_TVAL_INCREF(thr, &h_bound->this_binding);
35555
35556 bound_nargs = n_prevbound + nargs;
35557 if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
35558 DUK_DCERROR_RANGE_INVALID_COUNT(thr);
35559 }
35560 tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
35561 DUK_ASSERT(tv_res != NULL || bound_nargs == 0);
35562 DUK_ASSERT(h_bound->args == NULL);
35563 DUK_ASSERT(h_bound->nargs == 0);
35564 h_bound->args = tv_res;
35565 h_bound->nargs = bound_nargs;
35566
35567 DUK_ASSERT(n_prevbound >= 0);
35568 duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
35569 DUK_ASSERT(nargs >= 0);
35570 duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
35571
35572 /* [ thisArg arg1 ... argN func boundFunc ] */
35573
35574 /* Bound function 'length' property is interesting.
35575 * For lightfuncs, simply read the virtual property.
35576 */
35577 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
35578 bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */
35579 if (bound_len < nargs) {
35580 bound_len = 0;
35581 } else {
35582 bound_len -= nargs;
35583 }
35584 if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
35585 bound_len = (duk_int_t) DUK_UINT32_MAX;
35586 }
35587 duk_pop(thr);
35588 DUK_ASSERT(bound_len >= 0);
35589 tv_tmp = thr->valstack_top++;
35590 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
35591 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
35592 DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */
35593 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
35594
35595 /* XXX: could these be virtual? */
35596 /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
35597 duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
35598 duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
35599
35600 /* Function name and fileName (non-standard). */
35601 duk_push_literal(thr, "bound "); /* ES2015 19.2.3.2. */
35602 duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
35603 if (!duk_is_string_notsymbol(thr, -1)) {
35604 /* ES2015 has requirement to check that .name of target is a string
35605 * (also must check for Symbol); if not, targetName should be the
35606 * empty string. ES2015 19.2.3.2.
35607 */
35608 duk_pop(thr);
35609 duk_push_hstring_empty(thr);
35610 }
35611 duk_concat(thr, 2);
35612 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
35613#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
35614 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
35615 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
35616#endif
35617
35618 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
35619
35620 return 1;
35621}
35622#endif /* DUK_USE_FUNCTION_BUILTIN */
35623
35624/* %NativeFunctionPrototype% .length getter. */
35625DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
35626 duk_tval *tv;
35627 duk_hnatfunc *h;
35628 duk_int16_t func_nargs;
35629
35630 tv = duk_get_borrowed_this_tval(thr);
35631 DUK_ASSERT(tv != NULL);
35632
35633 if (DUK_TVAL_IS_OBJECT(tv)) {
35634 h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
35635 DUK_ASSERT(h != NULL);
35636 if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
35637 goto fail_type;
35638 }
35639 func_nargs = h->nargs;
35640 duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
35641 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
35642 duk_small_uint_t lf_flags;
35643 duk_small_uint_t lf_len;
35644
35645 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
35646 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
35647 duk_push_uint(thr, lf_len);
35648 } else {
35649 goto fail_type;
35650 }
35651 return 1;
35652
35653 fail_type:
35654 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
35655}
35656
35657/* %NativeFunctionPrototype% .name getter. */
35658DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
35659 duk_tval *tv;
35660 duk_hnatfunc *h;
35661
35662 tv = duk_get_borrowed_this_tval(thr);
35663 DUK_ASSERT(tv != NULL);
35664
35665 if (DUK_TVAL_IS_OBJECT(tv)) {
35666 h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
35667 DUK_ASSERT(h != NULL);
35668 if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
35669 goto fail_type;
35670 }
35671#if 0
35672 duk_push_hnatfunc_name(thr, h);
35673#endif
35674 duk_push_hstring_empty(thr);
35675 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
35676 duk_push_lightfunc_name(thr, tv);
35677 } else {
35678 goto fail_type;
35679 }
35680 return 1;
35681
35682 fail_type:
35683 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
35684}
35685
35686#if defined(DUK_USE_SYMBOL_BUILTIN)
35687DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) {
35688 /* This binding: RHS, stack index 0: LHS. */
35689 duk_bool_t ret;
35690
35691 ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr));
35692 duk_push_boolean(thr, ret);
35693 return 1;
35694}
35695#endif /* DUK_USE_SYMBOL_BUILTIN */
35696#line 1 "duk_bi_global.c"
35697/*
35698 * Global object built-ins
35699 */
35700
35701/* #include duk_internal.h -> already included */
35702
35703/*
35704 * Encoding/decoding helpers
35705 */
35706
35707/* XXX: Could add fast path (for each transform callback) with direct byte
35708 * lookups (no shifting) and no explicit check for x < 0x80 before table
35709 * lookup.
35710 */
35711
35712/* Macros for creating and checking bitmasks for character encoding.
35713 * Bit number is a bit counterintuitive, but minimizes code size.
35714 */
35715#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
35716 ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
35717 ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
35718 ))
35719#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
35720
35721/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
35722DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
35723 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
35724 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
35725 DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
35726 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
35727 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
35728 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
35729 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
35730 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
35731};
35732
35733/* E5.1 Section 15.1.3.4: uriUnescaped */
35734DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
35735 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
35736 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
35737 DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
35738 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
35739 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
35740 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
35741 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
35742 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
35743};
35744
35745/* E5.1 Section 15.1.3.1: uriReserved + '#' */
35746DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
35747 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
35748 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
35749 DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
35750 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
35751 DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
35752 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
35753 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
35754 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
35755};
35756
35757/* E5.1 Section 15.1.3.2: empty */
35758DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
35759 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
35760 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
35761 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
35762 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
35763 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
35764 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
35765 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
35766 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
35767};
35768
35769#if defined(DUK_USE_SECTION_B)
35770/* E5.1 Section B.2.2, step 7. */
35771DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
35772 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
35773 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
35774 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
35775 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
35776 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
35777 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
35778 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
35779 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
35780};
35781#endif /* DUK_USE_SECTION_B */
35782
35783typedef struct {
35784 duk_hthread *thr;
35785 duk_hstring *h_str;
35786 duk_bufwriter_ctx bw;
35787 const duk_uint8_t *p;
35788 const duk_uint8_t *p_start;
35789 const duk_uint8_t *p_end;
35790} duk__transform_context;
35791
35792typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
35793
35794/* XXX: refactor and share with other code */
35795DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
35796 duk_small_int_t ch;
35797 duk_small_int_t t = 0;
35798
35799 while (n > 0) {
35800 t = t * 16;
35801 ch = (duk_small_int_t) duk_hex_dectab[*p++];
35802 if (DUK_LIKELY(ch >= 0)) {
35803 t += ch;
35804 } else {
35805 return -1;
35806 }
35807 n--;
35808 }
35809 return t;
35810}
35811
35812DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) {
35813 duk__transform_context tfm_ctx_alloc;
35814 duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
35815 duk_codepoint_t cp;
35816
35817 tfm_ctx->thr = thr;
35818
35819 tfm_ctx->h_str = duk_to_hstring(thr, 0);
35820 DUK_ASSERT(tfm_ctx->h_str != NULL);
35821
35822 DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
35823
35824 tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
35825 tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
35826 tfm_ctx->p = tfm_ctx->p_start;
35827
35828 while (tfm_ctx->p < tfm_ctx->p_end) {
35829 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
35830 callback(tfm_ctx, udata, cp);
35831 }
35832
35833 DUK_BW_COMPACT(thr, &tfm_ctx->bw);
35834
35835 (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */
35836 return 1;
35837}
35838
35839DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
35840 duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
35841 duk_small_int_t len;
35842 duk_codepoint_t cp1, cp2;
35843 duk_small_int_t i, t;
35844 const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
35845
35846 /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
35847 * Codepoint range is restricted so this is a slightly too large
35848 * but doesn't matter.
35849 */
35850 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
35851
35852 if (cp < 0) {
35853 goto uri_error;
35854 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
35855 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
35856 return;
35857 } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
35858 goto uri_error;
35859 } else if (cp >= 0xd800L && cp <= 0xdbffL) {
35860 /* Needs lookahead */
35861 if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
35862 goto uri_error;
35863 }
35864 if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
35865 goto uri_error;
35866 }
35867 cp1 = cp;
35868 cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
35869 } else if (cp > 0x10ffffL) {
35870 /* Although we can allow non-BMP characters (they'll decode
35871 * back into surrogate pairs), we don't allow extended UTF-8
35872 * characters; they would encode to URIs which won't decode
35873 * back because of strict UTF-8 checks in URI decoding.
35874 * (However, we could just as well allow them here.)
35875 */
35876 goto uri_error;
35877 } else {
35878 /* Non-BMP characters within valid UTF-8 range: encode as is.
35879 * They'll decode back into surrogate pairs if the escaped
35880 * output is decoded.
35881 */
35882 ;
35883 }
35884
35885 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
35886 for (i = 0; i < len; i++) {
35887 t = (duk_small_int_t) xutf8_buf[i];
35888 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
35889 &tfm_ctx->bw,
35890 DUK_ASC_PERCENT,
35891 (duk_uint8_t) duk_uc_nybbles[t >> 4],
35892 (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
35893 }
35894
35895 return;
35896
35897 uri_error:
35898 DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
35899 DUK_WO_NORETURN(return;);
35900}
35901
35902DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
35903 const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
35904 duk_small_uint_t utf8_blen;
35905 duk_codepoint_t min_cp;
35906 duk_small_int_t t; /* must be signed */
35907 duk_small_uint_t i;
35908
35909 /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
35910 * percent escape path writes max two times CESU-8 encoded BMP length.
35911 */
35912 DUK_BW_ENSURE(tfm_ctx->thr,
35913 &tfm_ctx->bw,
35914 (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
35915 DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
35916
35917 if (cp == (duk_codepoint_t) '%') {
35918 const duk_uint8_t *p = tfm_ctx->p;
35919 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
35920
35921 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
35922
35923 if (left < 2) {
35924 goto uri_error;
35925 }
35926
35927 t = duk__decode_hex_escape(p, 2);
35928 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
35929 if (t < 0) {
35930 goto uri_error;
35931 }
35932
35933 if (t < 0x80) {
35934 if (DUK__CHECK_BITMASK(reserved_table, t)) {
35935 /* decode '%xx' to '%xx' if decoded char in reserved set */
35936 DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
35937 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
35938 &tfm_ctx->bw,
35939 DUK_ASC_PERCENT,
35940 p[0],
35941 p[1]);
35942 } else {
35943 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
35944 }
35945 tfm_ctx->p += 2;
35946 return;
35947 }
35948
35949 /* Decode UTF-8 codepoint from a sequence of hex escapes. The
35950 * first byte of the sequence has been decoded to 't'.
35951 *
35952 * Note that UTF-8 validation must be strict according to the
35953 * specification: E5.1 Section 15.1.3, decode algorithm step
35954 * 4.d.vii.8. URIError from non-shortest encodings is also
35955 * specifically noted in the spec.
35956 */
35957
35958 DUK_ASSERT(t >= 0x80);
35959 if (t < 0xc0) {
35960 /* continuation byte */
35961 goto uri_error;
35962 } else if (t < 0xe0) {
35963 /* 110x xxxx; 2 bytes */
35964 utf8_blen = 2;
35965 min_cp = 0x80L;
35966 cp = t & 0x1f;
35967 } else if (t < 0xf0) {
35968 /* 1110 xxxx; 3 bytes */
35969 utf8_blen = 3;
35970 min_cp = 0x800L;
35971 cp = t & 0x0f;
35972 } else if (t < 0xf8) {
35973 /* 1111 0xxx; 4 bytes */
35974 utf8_blen = 4;
35975 min_cp = 0x10000L;
35976 cp = t & 0x07;
35977 } else {
35978 /* extended utf-8 not allowed for URIs */
35979 goto uri_error;
35980 }
35981
35982 if (left < utf8_blen * 3 - 1) {
35983 /* '%xx%xx...%xx', p points to char after first '%' */
35984 goto uri_error;
35985 }
35986
35987 p += 3;
35988 for (i = 1; i < utf8_blen; i++) {
35989 /* p points to digit part ('%xy', p points to 'x') */
35990 t = duk__decode_hex_escape(p, 2);
35991 DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
35992 (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
35993 if (t < 0) {
35994 goto uri_error;
35995 }
35996 if ((t & 0xc0) != 0x80) {
35997 goto uri_error;
35998 }
35999 cp = (cp << 6) + (t & 0x3f);
36000 p += 3;
36001 }
36002 p--; /* p overshoots */
36003 tfm_ctx->p = p;
36004
36005 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
36006
36007 if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
36008 goto uri_error;
36009 }
36010
36011 /* The E5.1 algorithm checks whether or not a decoded codepoint
36012 * is below 0x80 and perhaps may be in the "reserved" set.
36013 * This seems pointless because the single byte UTF-8 case is
36014 * handled separately, and non-shortest encodings are rejected.
36015 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
36016 * the reserved set.
36017 */
36018
36019 /* utf-8 validation ensures these */
36020 DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
36021
36022 if (cp >= 0x10000L) {
36023 cp -= 0x10000L;
36024 DUK_ASSERT(cp < 0x100000L);
36025
36026 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
36027 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L));
36028 } else {
36029 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
36030 }
36031 } else {
36032 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
36033 }
36034 return;
36035
36036 uri_error:
36037 DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
36038 DUK_WO_NORETURN(return;);
36039}
36040
36041#if defined(DUK_USE_SECTION_B)
36042DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
36043 DUK_UNREF(udata);
36044
36045 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
36046
36047 if (cp < 0) {
36048 goto esc_error;
36049 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
36050 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
36051 } else if (cp < 0x100L) {
36052 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
36053 &tfm_ctx->bw,
36054 (duk_uint8_t) DUK_ASC_PERCENT,
36055 (duk_uint8_t) duk_uc_nybbles[cp >> 4],
36056 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
36057 } else if (cp < 0x10000L) {
36058 DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
36059 &tfm_ctx->bw,
36060 (duk_uint8_t) DUK_ASC_PERCENT,
36061 (duk_uint8_t) DUK_ASC_LC_U,
36062 (duk_uint8_t) duk_uc_nybbles[cp >> 12],
36063 (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
36064 (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
36065 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
36066 } else {
36067 /* Characters outside BMP cannot be escape()'d. We could
36068 * encode them as surrogate pairs (for codepoints inside
36069 * valid UTF-8 range, but not extended UTF-8). Because
36070 * escape() and unescape() are legacy functions, we don't.
36071 */
36072 goto esc_error;
36073 }
36074
36075 return;
36076
36077 esc_error:
36078 DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
36079 DUK_WO_NORETURN(return;);
36080}
36081
36082DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
36083 duk_small_int_t t;
36084
36085 DUK_UNREF(udata);
36086
36087 if (cp == (duk_codepoint_t) '%') {
36088 const duk_uint8_t *p = tfm_ctx->p;
36089 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
36090
36091 if (left >= 5 && p[0] == 'u' &&
36092 ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
36093 cp = (duk_codepoint_t) t;
36094 tfm_ctx->p += 5;
36095 } else if (left >= 2 &&
36096 ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
36097 cp = (duk_codepoint_t) t;
36098 tfm_ctx->p += 2;
36099 }
36100 }
36101
36102 DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
36103}
36104#endif /* DUK_USE_SECTION_B */
36105
36106/*
36107 * Eval
36108 *
36109 * Eval needs to handle both a "direct eval" and an "indirect eval".
36110 * Direct eval handling needs access to the caller's activation so that its
36111 * lexical environment can be accessed. A direct eval is only possible from
36112 * ECMAScript code; an indirect eval call is possible also from C code.
36113 * When an indirect eval call is made from C code, there may not be a
36114 * calling activation at all which needs careful handling.
36115 */
36116
36117DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
36118 duk_hstring *h;
36119 duk_activation *act_caller;
36120 duk_activation *act_eval;
36121 duk_hcompfunc *func;
36122 duk_hobject *outer_lex_env;
36123 duk_hobject *outer_var_env;
36124 duk_bool_t this_to_global = 1;
36125 duk_small_uint_t comp_flags;
36126 duk_int_t level = -2;
36127 duk_small_uint_t call_flags;
36128
36129 DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */
36130 DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
36131 DUK_ASSERT(thr->callstack_curr != NULL);
36132 DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
36133 (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
36134
36135 /*
36136 * callstack_top - 1 --> this function
36137 * callstack_top - 2 --> caller (may not exist)
36138 *
36139 * If called directly from C, callstack_top might be 1. If calling
36140 * activation doesn't exist, call must be indirect.
36141 */
36142
36143 h = duk_get_hstring_notsymbol(thr, 0);
36144 if (!h) {
36145 /* Symbol must be returned as is, like any non-string values. */
36146 return 1; /* return arg as-is */
36147 }
36148
36149#if defined(DUK_USE_DEBUGGER_SUPPORT)
36150 /* NOTE: level is used only by the debugger and should never be present
36151 * for an ECMAScript eval().
36152 */
36153 DUK_ASSERT(level == -2); /* by default, use caller's environment */
36154 if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
36155 level = duk_get_int(thr, 1);
36156 }
36157 DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
36158#endif
36159
36160 /* [ source ] */
36161
36162 comp_flags = DUK_COMPILE_EVAL;
36163 act_eval = thr->callstack_curr; /* this function */
36164 DUK_ASSERT(act_eval != NULL);
36165 act_caller = duk_hthread_get_activation_for_level(thr, level);
36166 if (act_caller != NULL) {
36167 /* Have a calling activation, check for direct eval (otherwise
36168 * assume indirect eval.
36169 */
36170 if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
36171 (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
36172 /* Only direct eval inherits strictness from calling code
36173 * (E5.1 Section 10.1.1).
36174 */
36175 comp_flags |= DUK_COMPILE_STRICT;
36176 }
36177 } else {
36178 DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
36179 }
36180
36181 duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
36182 duk_js_compile(thr,
36183 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
36184 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
36185 comp_flags);
36186 func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
36187 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
36188
36189 /* [ source template ] */
36190
36191 /* E5 Section 10.4.2 */
36192
36193 if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
36194 DUK_ASSERT(thr->callstack_top >= 2);
36195 DUK_ASSERT(act_caller != NULL);
36196 if (act_caller->lex_env == NULL) {
36197 DUK_ASSERT(act_caller->var_env == NULL);
36198 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
36199
36200 /* this may have side effects, so re-lookup act */
36201 duk_js_init_activation_environment_records_delayed(thr, act_caller);
36202 }
36203 DUK_ASSERT(act_caller->lex_env != NULL);
36204 DUK_ASSERT(act_caller->var_env != NULL);
36205
36206 this_to_global = 0;
36207
36208 if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
36209 duk_hdecenv *new_env;
36210 duk_hobject *act_lex_env;
36211
36212 DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
36213 "var_env and lex_env to a fresh env, "
36214 "this_binding to caller's this_binding"));
36215
36216 act_lex_env = act_caller->lex_env;
36217
36218 new_env = duk_hdecenv_alloc(thr,
36219 DUK_HOBJECT_FLAG_EXTENSIBLE |
36220 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
36221 DUK_ASSERT(new_env != NULL);
36222 duk_push_hobject(thr, (duk_hobject *) new_env);
36223
36224 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
36225 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env);
36226 DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env);
36227 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
36228
36229 outer_lex_env = (duk_hobject *) new_env;
36230 outer_var_env = (duk_hobject *) new_env;
36231
36232 duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
36233
36234 /* compiler's responsibility */
36235 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
36236 } else {
36237 DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
36238 "var_env and lex_env to caller's envs, "
36239 "this_binding to caller's this_binding"));
36240
36241 outer_lex_env = act_caller->lex_env;
36242 outer_var_env = act_caller->var_env;
36243
36244 /* compiler's responsibility */
36245 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
36246 }
36247 } else {
36248 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
36249 "global object, this_binding to global object"));
36250
36251 this_to_global = 1;
36252 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
36253 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
36254 }
36255
36256 /* Eval code doesn't need an automatic .prototype object. */
36257 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
36258
36259 /* [ env? source template closure ] */
36260
36261 if (this_to_global) {
36262 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
36263 duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
36264 } else {
36265 duk_tval *tv;
36266 DUK_ASSERT(thr->callstack_top >= 2);
36267 DUK_ASSERT(act_caller != NULL);
36268 tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */
36269 DUK_ASSERT(tv >= thr->valstack);
36270 duk_push_tval(thr, tv);
36271 }
36272
36273 DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
36274 (duk_heaphdr *) outer_lex_env,
36275 (duk_heaphdr *) outer_var_env,
36276 duk_get_tval(thr, -1)));
36277
36278 /* [ env? source template closure this ] */
36279
36280 call_flags = 0;
36281 if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
36282 /* Set DIRECT_EVAL flag for the call; it's not strictly
36283 * needed for the 'inner' eval call (the eval body) but
36284 * current new.target implementation expects to find it
36285 * so it can traverse direct eval chains up to the real
36286 * calling function.
36287 */
36288 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
36289 }
36290 duk_handle_call_unprotected_nargs(thr, 0, call_flags);
36291
36292 /* [ env? source template result ] */
36293
36294 return 1;
36295}
36296
36297/*
36298 * Parsing of ints and floats
36299 */
36300
36301#if defined(DUK_USE_GLOBAL_BUILTIN)
36302DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
36303 duk_int32_t radix;
36304 duk_small_uint_t s2n_flags;
36305
36306 DUK_ASSERT_TOP(thr, 2);
36307 duk_to_string(thr, 0); /* Reject symbols. */
36308
36309 radix = duk_to_int32(thr, 1);
36310
36311 /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
36312 * ES2015 0o123 or 0b10001.
36313 */
36314 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
36315 DUK_S2N_FLAG_ALLOW_GARBAGE |
36316 DUK_S2N_FLAG_ALLOW_PLUS |
36317 DUK_S2N_FLAG_ALLOW_MINUS |
36318 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
36319 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
36320
36321 /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
36322 *
36323 * Don't autodetect octals (from leading zeroes), require user code to
36324 * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
36325 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
36326 */
36327
36328 if (radix != 0) {
36329 if (radix < 2 || radix > 36) {
36330 goto ret_nan;
36331 }
36332 if (radix != 16) {
36333 s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
36334 }
36335 } else {
36336 radix = 10;
36337 }
36338
36339 duk_dup_0(thr);
36340 duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags);
36341 return 1;
36342
36343 ret_nan:
36344 duk_push_nan(thr);
36345 return 1;
36346}
36347#endif /* DUK_USE_GLOBAL_BUILTIN */
36348
36349#if defined(DUK_USE_GLOBAL_BUILTIN)
36350DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
36351 duk_small_uint_t s2n_flags;
36352
36353 DUK_ASSERT_TOP(thr, 1);
36354 duk_to_string(thr, 0); /* Reject symbols. */
36355
36356 /* XXX: check flags */
36357 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
36358 DUK_S2N_FLAG_ALLOW_EXP |
36359 DUK_S2N_FLAG_ALLOW_GARBAGE |
36360 DUK_S2N_FLAG_ALLOW_PLUS |
36361 DUK_S2N_FLAG_ALLOW_MINUS |
36362 DUK_S2N_FLAG_ALLOW_INF |
36363 DUK_S2N_FLAG_ALLOW_FRAC |
36364 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
36365 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
36366 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
36367
36368 duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
36369 return 1;
36370}
36371#endif /* DUK_USE_GLOBAL_BUILTIN */
36372
36373/*
36374 * Number checkers
36375 */
36376
36377#if defined(DUK_USE_GLOBAL_BUILTIN)
36378DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
36379 duk_double_t d = duk_to_number(thr, 0);
36380 duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d));
36381 return 1;
36382}
36383#endif /* DUK_USE_GLOBAL_BUILTIN */
36384
36385#if defined(DUK_USE_GLOBAL_BUILTIN)
36386DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
36387 duk_double_t d = duk_to_number(thr, 0);
36388 duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d));
36389 return 1;
36390}
36391#endif /* DUK_USE_GLOBAL_BUILTIN */
36392
36393/*
36394 * URI handling
36395 */
36396
36397#if defined(DUK_USE_GLOBAL_BUILTIN)
36398DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
36399 return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
36400}
36401
36402DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
36403 return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
36404}
36405
36406DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
36407 return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
36408}
36409
36410DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
36411 return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
36412}
36413
36414#if defined(DUK_USE_SECTION_B)
36415DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
36416 return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL);
36417}
36418
36419DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
36420 return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL);
36421}
36422#endif /* DUK_USE_SECTION_B */
36423#endif /* DUK_USE_GLOBAL_BUILTIN */
36424
36425/* automatic undefs */
36426#undef DUK__CHECK_BITMASK
36427#undef DUK__MKBITS
36428#line 1 "duk_bi_json.c"
36429/*
36430 * JSON built-ins.
36431 *
36432 * See doc/json.rst.
36433 *
36434 * Codepoints are handled as duk_uint_fast32_t to ensure that the full
36435 * unsigned 32-bit range is supported. This matters to e.g. JX.
36436 *
36437 * Input parsing doesn't do an explicit end-of-input check at all. This is
36438 * safe: input string data is always NUL-terminated (0x00) and valid JSON
36439 * inputs never contain plain NUL characters, so that as long as syntax checks
36440 * are correct, we'll never read past the NUL. This approach reduces code size
36441 * and improves parsing performance, but it's critical that syntax checks are
36442 * indeed correct!
36443 */
36444
36445/* #include duk_internal.h -> already included */
36446
36447#if defined(DUK_USE_JSON_SUPPORT)
36448
36449/*
36450 * Local defines and forward declarations.
36451 */
36452
36453#define DUK__JSON_DECSTR_BUFSIZE 128
36454#define DUK__JSON_DECSTR_CHUNKSIZE 64
36455#define DUK__JSON_ENCSTR_CHUNKSIZE 64
36456#define DUK__JSON_STRINGIFY_BUFSIZE 128
36457#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */
36458
36459DUK_LOCAL_DECL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx);
36460DUK_LOCAL_DECL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx);
36461#if defined(DUK_USE_JX)
36462DUK_LOCAL_DECL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx);
36463#endif
36464DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx);
36465DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
36466DUK_LOCAL_DECL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
36467DUK_LOCAL_DECL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
36468DUK_LOCAL_DECL void duk__json_dec_string(duk_json_dec_ctx *js_ctx);
36469#if defined(DUK_USE_JX)
36470DUK_LOCAL_DECL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx);
36471DUK_LOCAL_DECL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx);
36472DUK_LOCAL_DECL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx);
36473#endif
36474DUK_LOCAL_DECL void duk__json_dec_number(duk_json_dec_ctx *js_ctx);
36475DUK_LOCAL_DECL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx);
36476DUK_LOCAL_DECL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx);
36477DUK_LOCAL_DECL void duk__json_dec_object(duk_json_dec_ctx *js_ctx);
36478DUK_LOCAL_DECL void duk__json_dec_array(duk_json_dec_ctx *js_ctx);
36479DUK_LOCAL_DECL void duk__json_dec_value(duk_json_dec_ctx *js_ctx);
36480DUK_LOCAL_DECL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx);
36481
36482DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
36483DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
36484DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
36485DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
36486#if defined(DUK_USE_FASTINT)
36487DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
36488#endif
36489DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
36490DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q);
36491DUK_LOCAL_DECL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
36492DUK_LOCAL_DECL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
36493DUK_LOCAL_DECL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
36494DUK_LOCAL_DECL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
36495DUK_LOCAL_DECL void duk__json_enc_object(duk_json_enc_ctx *js_ctx);
36496DUK_LOCAL_DECL void duk__json_enc_array(duk_json_enc_ctx *js_ctx);
36497DUK_LOCAL_DECL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
36498DUK_LOCAL_DECL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv);
36499DUK_LOCAL_DECL void duk__json_enc_double(duk_json_enc_ctx *js_ctx);
36500#if defined(DUK_USE_FASTINT)
36501DUK_LOCAL_DECL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
36502#endif
36503#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36504DUK_LOCAL_DECL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
36505DUK_LOCAL_DECL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
36506#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
36507DUK_LOCAL_DECL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
36508#endif
36509#endif
36510#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
36511DUK_LOCAL_DECL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
36512#endif
36513DUK_LOCAL_DECL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
36514
36515/*
36516 * Helper tables
36517 */
36518
36519#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
36520DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
36521 /* 0x00 ... 0x7f: as is
36522 * 0x80: escape generically
36523 * 0x81: slow path
36524 * 0xa0 ... 0xff: backslash + one char
36525 */
36526
36527 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
36528 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
36529 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
36530 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
36531 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
36532 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
36533 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
36534 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
36535 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36536 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36537 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36538 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36539 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36540 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36541 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
36542 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
36543};
36544#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
36545DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
36546 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
36547 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
36548 DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
36549 DUK_ASC_LC_F, DUK_ASC_LC_R
36550};
36551#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
36552
36553#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
36554DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
36555 /* 0x00: slow path
36556 * other: as is
36557 */
36558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36560 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
36561 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
36562 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
36563 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
36564 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
36565 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
36566 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
36567 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
36568 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
36569 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
36570 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
36571 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
36572 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
36573 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
36574};
36575#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
36576
36577#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
36578DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
36579 /* 0x00: finish (non-white)
36580 * 0x01: continue
36581 */
36582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
36583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36584 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
36598};
36599#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
36600
36601#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
36602DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
36603 /* 0x00: finish (not part of number)
36604 * 0x01: continue
36605 */
36606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36607 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
36609 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36610 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36612 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
36622};
36623#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
36624
36625/*
36626 * Parsing implementation.
36627 *
36628 * JSON lexer is now separate from duk_lexer.c because there are numerous
36629 * small differences making it difficult to share the lexer.
36630 *
36631 * The parser here works with raw bytes directly; this works because all
36632 * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values
36633 * inside strings will be passed on without normalization; this is not a
36634 * compliance concern because compliant inputs will always be valid
36635 * CESU-8 encodings.
36636 */
36637
36638DUK_LOCAL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx) {
36639 /* Shared handler to minimize parser size. Cause will be
36640 * hidden, unfortunately, but we'll have an offset which
36641 * is often quite enough.
36642 */
36643 DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
36644 (long) (js_ctx->p - js_ctx->p_start));
36645 DUK_WO_NORETURN(return;);
36646}
36647
36648DUK_LOCAL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx) {
36649 const duk_uint8_t *p;
36650 duk_uint8_t t;
36651
36652 p = js_ctx->p;
36653 for (;;) {
36654 DUK_ASSERT(p <= js_ctx->p_end);
36655 t = *p;
36656
36657#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
36658 /* This fast path is pretty marginal in practice.
36659 * XXX: candidate for removal.
36660 */
36661 DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */
36662 if (duk__json_eatwhite_lookup[t] == 0) {
36663 break;
36664 }
36665#else /* DUK_USE_JSON_EATWHITE_FASTPATH */
36666 if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
36667 /* NUL also comes here. Comparison order matters, 0x20
36668 * is most common whitespace.
36669 */
36670 break;
36671 }
36672#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
36673 p++;
36674 }
36675 js_ctx->p = p;
36676}
36677
36678#if defined(DUK_USE_JX)
36679DUK_LOCAL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx) {
36680 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
36681 return *js_ctx->p;
36682}
36683#endif
36684
36685DUK_LOCAL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx) {
36686 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
36687 return *js_ctx->p++;
36688}
36689
36690DUK_LOCAL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
36691 duk__json_dec_eat_white(js_ctx);
36692 return duk__json_dec_get(js_ctx);
36693}
36694
36695/* For JX, expressing the whole unsigned 32-bit range matters. */
36696DUK_LOCAL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
36697 duk_small_uint_t i;
36698 duk_uint_fast32_t res = 0;
36699 duk_uint8_t x;
36700 duk_small_int_t t;
36701
36702 for (i = 0; i < n; i++) {
36703 /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
36704
36705 x = duk__json_dec_get(js_ctx);
36706 DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
36707 (long) i, (long) n, (long) res, (long) x));
36708
36709 /* x == 0x00 (EOF) causes syntax_error */
36710 DUK_ASSERT(duk_hex_dectab[0] == -1);
36711 t = duk_hex_dectab[x & 0xff];
36712 if (DUK_LIKELY(t >= 0)) {
36713 res = (res * 16) + (duk_uint_fast32_t) t;
36714 } else {
36715 /* catches EOF and invalid digits */
36716 goto syntax_error;
36717 }
36718 }
36719
36720 DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
36721 return res;
36722
36723 syntax_error:
36724 duk__json_dec_syntax_error(js_ctx);
36725 DUK_UNREACHABLE();
36726 return 0;
36727}
36728
36729DUK_LOCAL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
36730 duk_hstring *h;
36731 const duk_uint8_t *p;
36732 duk_uint8_t x, y;
36733
36734 /* First character has already been eaten and checked by the caller.
36735 * We can scan until a NUL in stridx string because no built-in strings
36736 * have internal NULs.
36737 */
36738
36739 DUK_ASSERT_STRIDX_VALID(stridx);
36740 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
36741 DUK_ASSERT(h != NULL);
36742
36743 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
36744 DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
36745
36746 for (;;) {
36747 x = *p;
36748 if (x == 0) {
36749 break;
36750 }
36751 y = duk__json_dec_get(js_ctx);
36752 if (x != y) {
36753 /* Catches EOF of JSON input. */
36754 goto syntax_error;
36755 }
36756 p++;
36757 }
36758
36759 return;
36760
36761 syntax_error:
36762 duk__json_dec_syntax_error(js_ctx);
36763 DUK_UNREACHABLE();
36764}
36765
36766DUK_LOCAL duk_small_int_t duk__json_dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
36767 duk_uint_fast32_t cp;
36768
36769 /* EOF (-1) will be cast to an unsigned value first
36770 * and then re-cast for the switch. In any case, it
36771 * will match the default case (syntax error).
36772 */
36773 cp = (duk_uint_fast32_t) duk__json_dec_get(js_ctx);
36774 switch (cp) {
36775 case DUK_ASC_BACKSLASH: break;
36776 case DUK_ASC_DOUBLEQUOTE: break;
36777 case DUK_ASC_SLASH: break;
36778 case DUK_ASC_LC_T: cp = 0x09; break;
36779 case DUK_ASC_LC_N: cp = 0x0a; break;
36780 case DUK_ASC_LC_R: cp = 0x0d; break;
36781 case DUK_ASC_LC_F: cp = 0x0c; break;
36782 case DUK_ASC_LC_B: cp = 0x08; break;
36783 case DUK_ASC_LC_U: {
36784 cp = duk__json_dec_decode_hex_escape(js_ctx, 4);
36785 break;
36786 }
36787#if defined(DUK_USE_JX)
36788 case DUK_ASC_UC_U: {
36789 if (js_ctx->flag_ext_custom) {
36790 cp = duk__json_dec_decode_hex_escape(js_ctx, 8);
36791 } else {
36792 return 1; /* syntax error */
36793 }
36794 break;
36795 }
36796 case DUK_ASC_LC_X: {
36797 if (js_ctx->flag_ext_custom) {
36798 cp = duk__json_dec_decode_hex_escape(js_ctx, 2);
36799 } else {
36800 return 1; /* syntax error */
36801 }
36802 break;
36803 }
36804#endif /* DUK_USE_JX */
36805 default:
36806 /* catches EOF (0x00) */
36807 return 1; /* syntax error */
36808 }
36809
36810 DUK_RAW_WRITEINC_XUTF8(*ext_p, cp);
36811
36812 return 0;
36813}
36814
36815DUK_LOCAL void duk__json_dec_string(duk_json_dec_ctx *js_ctx) {
36816 duk_hthread *thr = js_ctx->thr;
36817 duk_bufwriter_ctx bw_alloc;
36818 duk_bufwriter_ctx *bw;
36819 duk_uint8_t *q;
36820
36821 /* '"' was eaten by caller */
36822
36823 /* Note that we currently parse -bytes-, not codepoints.
36824 * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
36825 * so they'll simply pass through (valid UTF-8 or not).
36826 */
36827
36828 bw = &bw_alloc;
36829 DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
36830 q = DUK_BW_GET_PTR(js_ctx->thr, bw);
36831
36832#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
36833 for (;;) {
36834 duk_small_uint_t safe;
36835 duk_uint8_t b, x;
36836 const duk_uint8_t *p;
36837
36838 /* Select a safe loop count where no output checks are
36839 * needed assuming we won't encounter escapes. Input
36840 * bound checks are not necessary as a NUL (guaranteed)
36841 * will cause a SyntaxError before we read out of bounds.
36842 */
36843
36844 safe = DUK__JSON_DECSTR_CHUNKSIZE;
36845
36846 /* Ensure space for 1:1 output plus one escape. */
36847 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
36848
36849 p = js_ctx->p; /* temp copy, write back for next loop */
36850 for (;;) {
36851 if (safe == 0) {
36852 js_ctx->p = p;
36853 break;
36854 }
36855 safe--;
36856
36857 /* End of input (NUL) goes through slow path and causes SyntaxError. */
36858 DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
36859
36860 b = *p++;
36861 x = (duk_small_int_t) duk__json_decstr_lookup[b];
36862 if (DUK_LIKELY(x != 0)) {
36863 /* Fast path, decode as is. */
36864 *q++ = b;
36865 } else if (b == DUK_ASC_DOUBLEQUOTE) {
36866 js_ctx->p = p;
36867 goto found_quote;
36868 } else if (b == DUK_ASC_BACKSLASH) {
36869 /* We've ensured space for one escaped input; then
36870 * bail out and recheck (this makes escape handling
36871 * quite slow but it's uncommon).
36872 */
36873 js_ctx->p = p;
36874 if (duk__json_dec_string_escape(js_ctx, &q) != 0) {
36875 goto syntax_error;
36876 }
36877 break;
36878 } else {
36879 js_ctx->p = p;
36880 goto syntax_error;
36881 }
36882 }
36883 }
36884 found_quote:
36885#else /* DUK_USE_JSON_DECSTRING_FASTPATH */
36886 for (;;) {
36887 duk_uint8_t x;
36888
36889 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
36890
36891 x = duk__json_dec_get(js_ctx);
36892
36893 if (x == DUK_ASC_DOUBLEQUOTE) {
36894 break;
36895 } else if (x == DUK_ASC_BACKSLASH) {
36896 if (duk__json_dec_string_escape(js_ctx, &q) != 0) {
36897 goto syntax_error;
36898 }
36899 } else if (x < 0x20) {
36900 /* catches EOF (NUL) */
36901 goto syntax_error;
36902 } else {
36903 *q++ = (duk_uint8_t) x;
36904 }
36905 }
36906#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
36907
36908 DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
36909 (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */
36910
36911 /* [ ... str ] */
36912
36913 return;
36914
36915 syntax_error:
36916 duk__json_dec_syntax_error(js_ctx);
36917 DUK_UNREACHABLE();
36918}
36919
36920#if defined(DUK_USE_JX)
36921/* Decode a plain string consisting entirely of identifier characters.
36922 * Used to parse plain keys (e.g. "foo: 123").
36923 */
36924DUK_LOCAL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx) {
36925 duk_hthread *thr = js_ctx->thr;
36926 const duk_uint8_t *p;
36927 duk_small_int_t x;
36928
36929 /* Caller has already eaten the first char so backtrack one byte. */
36930
36931 js_ctx->p--; /* safe */
36932 p = js_ctx->p;
36933
36934 /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
36935 * parsing (which is correct except if there are non-shortest encodings).
36936 * There is also no need to check explicitly for end of input buffer as
36937 * the input is NUL padded and NUL will exit the parsing loop.
36938 *
36939 * Because no unescaping takes place, we can just scan to the end of the
36940 * plain string and intern from the input buffer.
36941 */
36942
36943 for (;;) {
36944 x = *p;
36945
36946 /* There is no need to check the first character specially here
36947 * (i.e. reject digits): the caller only accepts valid initial
36948 * characters and won't call us if the first character is a digit.
36949 * This also ensures that the plain string won't be empty.
36950 */
36951
36952 if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
36953 break;
36954 }
36955 p++;
36956 }
36957
36958 duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
36959 js_ctx->p = p;
36960
36961 /* [ ... str ] */
36962}
36963#endif /* DUK_USE_JX */
36964
36965#if defined(DUK_USE_JX)
36966DUK_LOCAL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx) {
36967 duk_hthread *thr = js_ctx->thr;
36968 const duk_uint8_t *p;
36969 duk_small_int_t x;
36970 void *voidptr;
36971
36972 /* Caller has already eaten the first character ('(') which we don't need. */
36973
36974 p = js_ctx->p;
36975
36976 for (;;) {
36977 x = *p;
36978
36979 /* Assume that the native representation never contains a closing
36980 * parenthesis.
36981 */
36982
36983 if (x == DUK_ASC_RPAREN) {
36984 break;
36985 } else if (x <= 0) {
36986 /* NUL term or -1 (EOF), NUL check would suffice */
36987 goto syntax_error;
36988 }
36989 p++;
36990 }
36991
36992 /* There is no need to NUL delimit the sscanf() call: trailing garbage is
36993 * ignored and there is always a NUL terminator which will force an error
36994 * if no error is encountered before it. It's possible that the scan
36995 * would scan further than between [js_ctx->p,p[ though and we'd advance
36996 * by less than the scanned value.
36997 *
36998 * Because pointers are platform specific, a failure to scan a pointer
36999 * results in a null pointer which is a better placeholder than a missing
37000 * value or an error.
37001 */
37002
37003 voidptr = NULL;
37004 (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
37005 duk_push_pointer(thr, voidptr);
37006 js_ctx->p = p + 1; /* skip ')' */
37007
37008 /* [ ... ptr ] */
37009
37010 return;
37011
37012 syntax_error:
37013 duk__json_dec_syntax_error(js_ctx);
37014 DUK_UNREACHABLE();
37015}
37016#endif /* DUK_USE_JX */
37017
37018#if defined(DUK_USE_JX)
37019DUK_LOCAL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx) {
37020 duk_hthread *thr = js_ctx->thr;
37021 const duk_uint8_t *p;
37022 duk_uint8_t *buf;
37023 duk_size_t src_len;
37024 duk_small_int_t x;
37025
37026 /* Caller has already eaten the first character ('|') which we don't need. */
37027
37028 p = js_ctx->p;
37029
37030 /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
37031 * and avoid creating a temporary buffer. However, there are some
37032 * differences which prevent trivial sharing:
37033 *
37034 * - Pipe char detection
37035 * - EOF detection
37036 * - Unknown length of input and output
37037 *
37038 * The best approach here would be a bufwriter and a reasonaly sized
37039 * safe inner loop (e.g. 64 output bytes at a time).
37040 */
37041
37042 for (;;) {
37043 x = *p;
37044
37045 /* This loop intentionally does not ensure characters are valid
37046 * ([0-9a-fA-F]) because the hex decode call below will do that.
37047 */
37048 if (x == DUK_ASC_PIPE) {
37049 break;
37050 } else if (x <= 0) {
37051 /* NUL term or -1 (EOF), NUL check would suffice */
37052 goto syntax_error;
37053 }
37054 p++;
37055 }
37056
37057 /* XXX: this is not very nice; unnecessary copy is made. */
37058 src_len = (duk_size_t) (p - js_ctx->p);
37059 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
37060 DUK_ASSERT(buf != NULL);
37061 duk_memcpy((void *) buf, (const void *) js_ctx->p, src_len);
37062 duk_hex_decode(thr, -1);
37063
37064 js_ctx->p = p + 1; /* skip '|' */
37065
37066 /* [ ... buf ] */
37067
37068 return;
37069
37070 syntax_error:
37071 duk__json_dec_syntax_error(js_ctx);
37072 DUK_UNREACHABLE();
37073}
37074#endif /* DUK_USE_JX */
37075
37076/* Parse a number, other than NaN or +/- Infinity */
37077DUK_LOCAL void duk__json_dec_number(duk_json_dec_ctx *js_ctx) {
37078 duk_hthread *thr = js_ctx->thr;
37079 const duk_uint8_t *p_start;
37080 const duk_uint8_t *p;
37081 duk_uint8_t x;
37082 duk_small_uint_t s2n_flags;
37083
37084 DUK_DDD(DUK_DDDPRINT("parse_number"));
37085
37086 p_start = js_ctx->p;
37087
37088 /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
37089 * string for strict number parsing.
37090 */
37091
37092 p = js_ctx->p;
37093 for (;;) {
37094 x = *p;
37095
37096 DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
37097 (const void *) p_start, (const void *) p,
37098 (const void *) js_ctx->p_end, (long) x));
37099
37100#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
37101 /* This fast path is pretty marginal in practice.
37102 * XXX: candidate for removal.
37103 */
37104 DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */
37105 if (duk__json_decnumber_lookup[x] == 0) {
37106 break;
37107 }
37108#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */
37109 if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
37110 (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
37111 x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
37112 /* Plus sign must be accepted for positive exponents
37113 * (e.g. '1.5e+2'). This clause catches NULs.
37114 */
37115 break;
37116 }
37117#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
37118 p++; /* safe, because matched (NUL causes a break) */
37119 }
37120 js_ctx->p = p;
37121
37122 DUK_ASSERT(js_ctx->p > p_start);
37123 duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start));
37124
37125 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
37126 DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
37127 DUK_S2N_FLAG_ALLOW_FRAC;
37128
37129 DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
37130 (duk_tval *) duk_get_tval(thr, -1)));
37131 duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
37132 if (duk_is_nan(thr, -1)) {
37133 duk__json_dec_syntax_error(js_ctx);
37134 }
37135 DUK_ASSERT(duk_is_number(thr, -1));
37136 DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
37137 (duk_tval *) duk_get_tval(thr, -1)));
37138
37139 /* [ ... num ] */
37140}
37141
37142DUK_LOCAL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
37143 duk_hthread *thr = js_ctx->thr;
37144 duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
37145
37146 /* c recursion check */
37147
37148 duk_native_stack_check(thr);
37149
37150 DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
37151 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
37152 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
37153 DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT);
37154 DUK_WO_NORETURN(return;);
37155 }
37156 js_ctx->recursion_depth++;
37157}
37158
37159DUK_LOCAL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
37160 /* c recursion check */
37161
37162 DUK_ASSERT(js_ctx->recursion_depth > 0);
37163 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
37164 js_ctx->recursion_depth--;
37165}
37166
37167DUK_LOCAL void duk__json_dec_object(duk_json_dec_ctx *js_ctx) {
37168 duk_hthread *thr = js_ctx->thr;
37169 duk_int_t key_count; /* XXX: a "first" flag would suffice */
37170 duk_uint8_t x;
37171
37172 DUK_DDD(DUK_DDDPRINT("parse_object"));
37173
37174 duk__json_dec_objarr_entry(js_ctx);
37175
37176 duk_push_object(thr);
37177
37178 /* Initial '{' has been checked and eaten by caller. */
37179
37180 key_count = 0;
37181 for (;;) {
37182 x = duk__json_dec_get_nonwhite(js_ctx);
37183
37184 DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
37185 (duk_tval *) duk_get_tval(thr, -1),
37186 (long) x, (long) key_count));
37187
37188 /* handle comma and closing brace */
37189
37190 if (x == DUK_ASC_COMMA && key_count > 0) {
37191 /* accept comma, expect new value */
37192 x = duk__json_dec_get_nonwhite(js_ctx);
37193 } else if (x == DUK_ASC_RCURLY) {
37194 /* eat closing brace */
37195 break;
37196 } else if (key_count == 0) {
37197 /* accept anything, expect first value (EOF will be
37198 * caught by key parsing below.
37199 */
37200 ;
37201 } else {
37202 /* catches EOF (NUL) and initial comma */
37203 goto syntax_error;
37204 }
37205
37206 /* parse key and value */
37207
37208 if (x == DUK_ASC_DOUBLEQUOTE) {
37209 duk__json_dec_string(js_ctx);
37210#if defined(DUK_USE_JX)
37211 } else if (js_ctx->flag_ext_custom &&
37212 duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
37213 duk__json_dec_plain_string(js_ctx);
37214#endif
37215 } else {
37216 goto syntax_error;
37217 }
37218
37219 /* [ ... obj key ] */
37220
37221 x = duk__json_dec_get_nonwhite(js_ctx);
37222 if (x != DUK_ASC_COLON) {
37223 goto syntax_error;
37224 }
37225
37226 duk__json_dec_value(js_ctx);
37227
37228 /* [ ... obj key val ] */
37229
37230 duk_xdef_prop_wec(thr, -3);
37231
37232 /* [ ... obj ] */
37233
37234 key_count++;
37235 }
37236
37237 /* [ ... obj ] */
37238
37239 DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
37240 (duk_tval *) duk_get_tval(thr, -1)));
37241
37242 duk__json_dec_objarr_exit(js_ctx);
37243 return;
37244
37245 syntax_error:
37246 duk__json_dec_syntax_error(js_ctx);
37247 DUK_UNREACHABLE();
37248}
37249
37250DUK_LOCAL void duk__json_dec_array(duk_json_dec_ctx *js_ctx) {
37251 duk_hthread *thr = js_ctx->thr;
37252 duk_uarridx_t arr_idx;
37253 duk_uint8_t x;
37254
37255 DUK_DDD(DUK_DDDPRINT("parse_array"));
37256
37257 duk__json_dec_objarr_entry(js_ctx);
37258
37259 duk_push_array(thr);
37260
37261 /* Initial '[' has been checked and eaten by caller. */
37262
37263 arr_idx = 0;
37264 for (;;) {
37265 x = duk__json_dec_get_nonwhite(js_ctx);
37266
37267 DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
37268 (duk_tval *) duk_get_tval(thr, -1),
37269 (long) x, (long) arr_idx));
37270
37271 /* handle comma and closing bracket */
37272
37273 if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
37274 /* accept comma, expect new value */
37275 ;
37276 } else if (x == DUK_ASC_RBRACKET) {
37277 /* eat closing bracket */
37278 break;
37279 } else if (arr_idx == 0) {
37280 /* accept anything, expect first value (EOF will be
37281 * caught by duk__json_dec_value() below.
37282 */
37283 js_ctx->p--; /* backtrack (safe) */
37284 } else {
37285 /* catches EOF (NUL) and initial comma */
37286 goto syntax_error;
37287 }
37288
37289 /* parse value */
37290
37291 duk__json_dec_value(js_ctx);
37292
37293 /* [ ... arr val ] */
37294
37295 duk_xdef_prop_index_wec(thr, -2, arr_idx);
37296 arr_idx++;
37297 }
37298
37299 /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
37300 * set the values.
37301 */
37302
37303 duk_set_length(thr, -1, arr_idx);
37304
37305 /* [ ... arr ] */
37306
37307 DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
37308 (duk_tval *) duk_get_tval(thr, -1)));
37309
37310 duk__json_dec_objarr_exit(js_ctx);
37311 return;
37312
37313 syntax_error:
37314 duk__json_dec_syntax_error(js_ctx);
37315 DUK_UNREACHABLE();
37316}
37317
37318DUK_LOCAL void duk__json_dec_value(duk_json_dec_ctx *js_ctx) {
37319 duk_hthread *thr = js_ctx->thr;
37320 duk_uint8_t x;
37321
37322 x = duk__json_dec_get_nonwhite(js_ctx);
37323
37324 DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
37325
37326 /* Note: duk__json_dec_req_stridx() backtracks one char */
37327
37328 if (x == DUK_ASC_DOUBLEQUOTE) {
37329 duk__json_dec_string(js_ctx);
37330 } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
37331#if defined(DUK_USE_JX)
37332 if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__json_dec_peek(js_ctx) == DUK_ASC_UC_I) {
37333 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
37334 duk_push_number(thr, -DUK_DOUBLE_INFINITY);
37335 } else {
37336#else
37337 { /* unconditional block */
37338#endif
37339 /* We already ate 'x', so backup one byte. */
37340 js_ctx->p--; /* safe */
37341 duk__json_dec_number(js_ctx);
37342 }
37343 } else if (x == DUK_ASC_LC_T) {
37344 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
37345 duk_push_true(thr);
37346 } else if (x == DUK_ASC_LC_F) {
37347 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
37348 duk_push_false(thr);
37349 } else if (x == DUK_ASC_LC_N) {
37350 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
37351 duk_push_null(thr);
37352#if defined(DUK_USE_JX)
37353 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
37354 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
37355 duk_push_undefined(thr);
37356 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
37357 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
37358 duk_push_nan(thr);
37359 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
37360 duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
37361 duk_push_number(thr, DUK_DOUBLE_INFINITY);
37362 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
37363 duk__json_dec_pointer(js_ctx);
37364 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
37365 duk__json_dec_buffer(js_ctx);
37366#endif
37367 } else if (x == DUK_ASC_LCURLY) {
37368 duk__json_dec_object(js_ctx);
37369 } else if (x == DUK_ASC_LBRACKET) {
37370 duk__json_dec_array(js_ctx);
37371 } else {
37372 /* catches EOF (NUL) */
37373 goto syntax_error;
37374 }
37375
37376 duk__json_dec_eat_white(js_ctx);
37377
37378 /* [ ... val ] */
37379 return;
37380
37381 syntax_error:
37382 duk__json_dec_syntax_error(js_ctx);
37383 DUK_UNREACHABLE();
37384}
37385
37386/* Recursive value reviver, implements the Walk() algorithm. The parsing
37387 * step ensures there is a reasonable depth limit to the input. However,
37388 * the reviver may create more depth by editing object or array entries, so
37389 * we have both C recursion limit and native stack checks here.
37390 */
37391DUK_LOCAL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
37392 duk_hthread *thr = js_ctx->thr;
37393 duk_hobject *h;
37394 duk_uarridx_t i, arr_len;
37395
37396 duk__json_dec_objarr_entry(js_ctx);
37397
37398 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
37399 (long) duk_get_top(thr),
37400 (duk_tval *) duk_get_tval(thr, -2),
37401 (duk_tval *) duk_get_tval(thr, -1)));
37402
37403 duk_dup_top(thr);
37404 duk_get_prop(thr, -3); /* -> [ ... holder name val ] */
37405
37406 h = duk_get_hobject(thr, -1);
37407 if (h != NULL) {
37408 if (duk_js_isarray_hobject(h)) {
37409 arr_len = (duk_uarridx_t) duk_get_length(thr, -1);
37410 for (i = 0; i < arr_len; i++) {
37411 /* [ ... holder name val ] */
37412
37413 DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
37414 (long) duk_get_top(thr), (long) i, (long) arr_len,
37415 (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
37416 (duk_tval *) duk_get_tval(thr, -1)));
37417
37418 duk_dup_top(thr);
37419 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
37420 duk__json_dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
37421
37422 if (duk_is_undefined(thr, -1)) {
37423 duk_pop(thr);
37424 duk_del_prop_index(thr, -1, i);
37425 } else {
37426 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
37427 * here but it currently makes some assumptions that might
37428 * not hold (e.g. that previous property is not an accessor).
37429 */
37430 duk_put_prop_index(thr, -2, i);
37431 }
37432 }
37433 } else {
37434 /* [ ... holder name val ] */
37435 duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
37436 while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
37437 DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
37438 (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5),
37439 (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3),
37440 (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
37441
37442 /* [ ... holder name val enum obj_key ] */
37443 duk_dup_m3(thr);
37444 duk_dup_m2(thr);
37445
37446 /* [ ... holder name val enum obj_key val obj_key ] */
37447 duk__json_dec_reviver_walk(js_ctx);
37448
37449 /* [ ... holder name val enum obj_key new_elem ] */
37450 if (duk_is_undefined(thr, -1)) {
37451 duk_pop(thr);
37452 duk_del_prop(thr, -3);
37453 } else {
37454 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
37455 * here but it currently makes some assumptions that might
37456 * not hold (e.g. that previous property is not an accessor).
37457 *
37458 * Using duk_put_prop() works incorrectly with '__proto__'
37459 * if the own property with that name has been deleted. This
37460 * does not happen normally, but a clever reviver can trigger
37461 * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
37462 */
37463 duk_put_prop(thr, -4);
37464 }
37465 }
37466 duk_pop(thr); /* pop enum */
37467 }
37468 }
37469
37470 /* [ ... holder name val ] */
37471
37472 duk_dup(thr, js_ctx->idx_reviver);
37473 duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */
37474 duk_call_method(thr, 2); /* -> [ ... res ] */
37475
37476 duk__json_dec_objarr_exit(js_ctx);
37477
37478 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
37479 (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
37480}
37481
37482/*
37483 * Stringify implementation.
37484 */
37485
37486#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
37487#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
37488#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h))
37489#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
37490#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p))
37491#endif
37492#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i))
37493#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx))
37494
37495DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
37496 DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
37497}
37498
37499DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
37500 DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
37501}
37502
37503DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
37504 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
37505}
37506
37507#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
37508DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
37509 DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
37510}
37511#endif
37512
37513DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
37514 duk_hstring *h;
37515
37516 DUK_ASSERT_STRIDX_VALID(stridx);
37517 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
37518 DUK_ASSERT(h != NULL);
37519
37520 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
37521}
37522
37523DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
37524 DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
37525 DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
37526}
37527
37528#define DUK__MKESC(nybbles,esc1,esc2) \
37529 (((duk_uint_fast32_t) (nybbles)) << 16) | \
37530 (((duk_uint_fast32_t) (esc1)) << 8) | \
37531 ((duk_uint_fast32_t) (esc2))
37532
37533DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
37534 duk_uint_fast32_t tmp;
37535 duk_small_uint_t dig;
37536
37537 DUK_UNREF(js_ctx);
37538
37539 /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
37540
37541 /* Select appropriate escape format automatically, and set 'tmp' to a
37542 * value encoding both the escape format character and the nybble count:
37543 *
37544 * (nybble_count << 16) | (escape_char1) | (escape_char2)
37545 */
37546
37547#if defined(DUK_USE_JX)
37548 if (DUK_LIKELY(cp < 0x100UL)) {
37549 if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) {
37550 tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
37551 } else {
37552 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
37553 }
37554 } else
37555#endif
37556 if (DUK_LIKELY(cp < 0x10000UL)) {
37557 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
37558 } else {
37559#if defined(DUK_USE_JX)
37560 if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) {
37561 tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
37562 } else
37563#endif
37564 {
37565 /* In compatible mode and standard JSON mode, output
37566 * something useful for non-BMP characters. This won't
37567 * roundtrip but will still be more or less readable and
37568 * more useful than an error.
37569 */
37570 tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
37571 }
37572 }
37573
37574 *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
37575 *q++ = (duk_uint8_t) (tmp & 0xff);
37576
37577 tmp = tmp >> 16;
37578 while (tmp > 0) {
37579 tmp--;
37580 dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
37581 *q++ = duk_lc_digits[dig];
37582 }
37583
37584 return q;
37585}
37586
37587DUK_LOCAL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
37588 const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */
37589 duk_size_t k_len;
37590 duk_codepoint_t cp;
37591
37592 DUK_ASSERT(k != NULL);
37593
37594 /* Accept ASCII strings which conform to identifier requirements
37595 * as being emitted without key quotes. Since we only accept ASCII
37596 * there's no need for actual decoding: 'p' is intentionally signed
37597 * so that bytes >= 0x80 extend to negative values and are rejected
37598 * as invalid identifier codepoints.
37599 */
37600
37601 if (js_ctx->flag_avoid_key_quotes) {
37602 k_len = DUK_HSTRING_GET_BYTELEN(k);
37603 p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
37604 p_end = p_start + k_len;
37605 p = p_start;
37606
37607 if (p == p_end) {
37608 /* Zero length string is not accepted without quotes */
37609 goto quote_normally;
37610 }
37611 cp = (duk_codepoint_t) (*p++);
37612 if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
37613 goto quote_normally;
37614 }
37615 while (p < p_end) {
37616 cp = (duk_codepoint_t) (*p++);
37617 if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
37618 goto quote_normally;
37619 }
37620 }
37621
37622 /* This seems faster than emitting bytes one at a time and
37623 * then potentially rewinding.
37624 */
37625 DUK__EMIT_HSTR(js_ctx, k);
37626 return;
37627 }
37628
37629 quote_normally:
37630 duk__json_enc_quote_string(js_ctx, k);
37631}
37632
37633/* The Quote(value) operation: quote a string.
37634 *
37635 * Stack policy: [ ] -> [ ].
37636 */
37637
37638DUK_LOCAL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
37639 duk_hthread *thr = js_ctx->thr;
37640 const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
37641 duk_uint8_t *q;
37642 duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */
37643
37644 DUK_DDD(DUK_DDDPRINT("duk__json_enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
37645
37646 DUK_ASSERT(h_str != NULL);
37647 p_start = DUK_HSTRING_GET_DATA(h_str);
37648 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
37649 p = p_start;
37650
37651 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
37652
37653 /* Encode string in small chunks, estimating the maximum expansion so that
37654 * there's no need to ensure space while processing the chunk.
37655 */
37656
37657 while (p < p_end) {
37658 duk_size_t left, now, space;
37659
37660 left = (duk_size_t) (p_end - p);
37661 now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
37662 DUK__JSON_ENCSTR_CHUNKSIZE : left);
37663
37664 /* Maximum expansion per input byte is 6:
37665 * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
37666 * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
37667 * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
37668 */
37669 space = now * 6;
37670 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
37671
37672 p_now = p + now;
37673
37674 while (p < p_now) {
37675#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
37676 duk_uint8_t b;
37677
37678 b = duk__json_quotestr_lookup[*p++];
37679 if (DUK_LIKELY(b < 0x80)) {
37680 /* Most input bytes go through here. */
37681 *q++ = b;
37682 } else if (b >= 0xa0) {
37683 *q++ = DUK_ASC_BACKSLASH;
37684 *q++ = (duk_uint8_t) (b - 0x80);
37685 } else if (b == 0x80) {
37686 cp = (duk_ucodepoint_t) (*(p - 1));
37687 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
37688 } else if (b == 0x7f && js_ctx->flag_ascii_only) {
37689 /* 0x7F is special */
37690 DUK_ASSERT(b == 0x81);
37691 cp = (duk_ucodepoint_t) 0x7f;
37692 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
37693 } else {
37694 DUK_ASSERT(b == 0x81);
37695 p--;
37696
37697 /* slow path is shared */
37698#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
37699 cp = *p;
37700
37701 if (DUK_LIKELY(cp <= 0x7f)) {
37702 /* ascii fast path: avoid decoding utf-8 */
37703 p++;
37704 if (cp == 0x22 || cp == 0x5c) {
37705 /* double quote or backslash */
37706 *q++ = DUK_ASC_BACKSLASH;
37707 *q++ = (duk_uint8_t) cp;
37708 } else if (cp < 0x20) {
37709 duk_uint_fast8_t esc_char;
37710
37711 /* This approach is a bit shorter than a straight
37712 * if-else-ladder and also a bit faster.
37713 */
37714 if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
37715 (esc_char = duk__json_quotestr_esc[cp]) != 0) {
37716 *q++ = DUK_ASC_BACKSLASH;
37717 *q++ = (duk_uint8_t) esc_char;
37718 } else {
37719 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
37720 }
37721 } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
37722 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
37723 } else {
37724 /* any other printable -> as is */
37725 *q++ = (duk_uint8_t) cp;
37726 }
37727 } else {
37728 /* slow path is shared */
37729#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
37730
37731 /* slow path decode */
37732
37733 /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
37734 * and go forward one byte. This is of course very lossy, but allows some kind
37735 * of output to be produced even for internal strings which don't conform to
37736 * XUTF-8. All standard ECMAScript strings are always CESU-8, so this behavior
37737 * does not violate the ECMAScript specification. The behavior is applied to
37738 * all modes, including ECMAScript standard JSON. Because the current XUTF-8
37739 * decoding is not very strict, this behavior only really affects initial bytes
37740 * and truncated codepoints.
37741 *
37742 * Another alternative would be to scan forwards to start of next codepoint
37743 * (or end of input) and emit just one replacement codepoint.
37744 */
37745
37746 p_tmp = p;
37747 if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
37748 /* Decode failed. */
37749 cp = *p_tmp;
37750 p = p_tmp + 1;
37751 }
37752
37753#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029)
37754 if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
37755#else
37756 if (js_ctx->flag_ascii_only) {
37757#endif
37758 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
37759 } else {
37760 /* as is */
37761 DUK_RAW_WRITEINC_XUTF8(q, cp);
37762 }
37763 }
37764 }
37765
37766 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
37767 }
37768
37769 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
37770}
37771
37772/* Encode a double (checked by caller) from stack top. Stack top may be
37773 * replaced by serialized string but is not popped (caller does that).
37774 */
37775DUK_LOCAL void duk__json_enc_double(duk_json_enc_ctx *js_ctx) {
37776 duk_hthread *thr;
37777 duk_tval *tv;
37778 duk_double_t d;
37779 duk_small_int_t c;
37780 duk_small_int_t s;
37781 duk_small_uint_t stridx;
37782 duk_small_uint_t n2s_flags;
37783 duk_hstring *h_str;
37784
37785 DUK_ASSERT(js_ctx != NULL);
37786 thr = js_ctx->thr;
37787 DUK_ASSERT(thr != NULL);
37788
37789 /* Caller must ensure 'tv' is indeed a double and not a fastint! */
37790 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
37791 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
37792 d = DUK_TVAL_GET_DOUBLE(tv);
37793
37794 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
37795 s = (duk_small_int_t) DUK_SIGNBIT(d);
37796 DUK_UNREF(s);
37797
37798 if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
37799 DUK_ASSERT(DUK_ISFINITE(d));
37800
37801#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37802 /* Negative zero needs special handling in JX/JC because
37803 * it would otherwise serialize to '0', not '-0'.
37804 */
37805 if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
37806 (js_ctx->flag_ext_custom_or_compatible))) {
37807 duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */
37808 } else
37809#endif /* DUK_USE_JX || DUK_USE_JC */
37810 {
37811 n2s_flags = 0;
37812 /* [ ... number ] -> [ ... string ] */
37813 duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags);
37814 }
37815 h_str = duk_known_hstring(thr, -1);
37816 DUK__EMIT_HSTR(js_ctx, h_str);
37817 return;
37818 }
37819
37820#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37821 if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
37822 DUK_JSON_FLAG_EXT_COMPATIBLE))) {
37823 stridx = DUK_STRIDX_LC_NULL;
37824 } else if (c == DUK_FP_NAN) {
37825 stridx = js_ctx->stridx_custom_nan;
37826 } else if (s == 0) {
37827 stridx = js_ctx->stridx_custom_posinf;
37828 } else {
37829 stridx = js_ctx->stridx_custom_neginf;
37830 }
37831#else
37832 stridx = DUK_STRIDX_LC_NULL;
37833#endif
37834 DUK__EMIT_STRIDX(js_ctx, stridx);
37835}
37836
37837#if defined(DUK_USE_FASTINT)
37838/* Encode a fastint from duk_tval ptr, no value stack effects. */
37839DUK_LOCAL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
37840 duk_int64_t v;
37841
37842 /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
37843 * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
37844 * (20 chars long). Alloc space for 64-bit range to be safe.
37845 */
37846 duk_uint8_t buf[20 + 1];
37847
37848 /* Caller must ensure 'tv' is indeed a fastint! */
37849 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
37850 v = DUK_TVAL_GET_FASTINT(tv);
37851
37852 /* XXX: There are no format strings in duk_config.h yet, could add
37853 * one for formatting duk_int64_t. For now, assumes "%lld" and that
37854 * "long long" type exists. Could also rely on C99 directly but that
37855 * won't work for older MSVC.
37856 */
37857 DUK_SPRINTF((char *) buf, "%lld", (long long) v);
37858 DUK__EMIT_CSTR(js_ctx, (const char *) buf);
37859}
37860#endif
37861
37862#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37863#if defined(DUK_USE_HEX_FASTPATH)
37864DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
37865 duk_uint8_t *q;
37866 duk_uint16_t *q16;
37867 duk_small_uint_t x;
37868 duk_size_t i, len_safe;
37869#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
37870 duk_bool_t shift_dst;
37871#endif
37872
37873 /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
37874 * For platforms where unaligned accesses are not allowed, shift 'dst'
37875 * ahead by 1 byte to get alignment and then duk_memmove() the result
37876 * in place. The faster encoding loop makes up the difference.
37877 * There's always space for one extra byte because a terminator always
37878 * follows the hex data and that's been accounted for by the caller.
37879 */
37880
37881#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
37882 q16 = (duk_uint16_t *) (void *) dst;
37883#else
37884 shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
37885 if (shift_dst) {
37886 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
37887 q16 = (duk_uint16_t *) (void *) (dst + 1);
37888 } else {
37889 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
37890 q16 = (duk_uint16_t *) (void *) dst;
37891 }
37892 DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
37893#endif
37894
37895 len_safe = src_len & ~0x03U;
37896 for (i = 0; i < len_safe; i += 4) {
37897 q16[0] = duk_hex_enctab[src[i]];
37898 q16[1] = duk_hex_enctab[src[i + 1]];
37899 q16[2] = duk_hex_enctab[src[i + 2]];
37900 q16[3] = duk_hex_enctab[src[i + 3]];
37901 q16 += 4;
37902 }
37903 q = (duk_uint8_t *) q16;
37904
37905#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
37906 if (shift_dst) {
37907 q--;
37908 duk_memmove((void *) dst, (const void *) (dst + 1), 2 * len_safe);
37909 DUK_ASSERT(dst + 2 * len_safe == q);
37910 }
37911#endif
37912
37913 for (; i < src_len; i++) {
37914 x = src[i];
37915 *q++ = duk_lc_digits[x >> 4];
37916 *q++ = duk_lc_digits[x & 0x0f];
37917 }
37918
37919 return q;
37920}
37921#else /* DUK_USE_HEX_FASTPATH */
37922DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
37923 const duk_uint8_t *p;
37924 const duk_uint8_t *p_end;
37925 duk_uint8_t *q;
37926 duk_small_uint_t x;
37927
37928 p = src;
37929 p_end = src + src_len;
37930 q = dst;
37931 while (p != p_end) {
37932 x = *p++;
37933 *q++ = duk_lc_digits[x >> 4];
37934 *q++ = duk_lc_digits[x & 0x0f];
37935 }
37936
37937 return q;
37938}
37939#endif /* DUK_USE_HEX_FASTPATH */
37940
37941DUK_LOCAL void duk__json_enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
37942 duk_hthread *thr;
37943 duk_uint8_t *q;
37944 duk_size_t space;
37945
37946 thr = js_ctx->thr;
37947
37948 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
37949 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
37950
37951 /* Buffer values are encoded in (lowercase) hex to make the
37952 * binary data readable. Base64 or similar would be more
37953 * compact but less readable, and the point of JX/JC
37954 * variants is to be as useful to a programmer as possible.
37955 */
37956
37957 /* The #if defined() clutter here needs to handle the three
37958 * cases: (1) JX+JC, (2) JX only, (3) JC only.
37959 */
37960
37961 /* Note: space must cater for both JX and JC. */
37962 space = 9 + buf_len * 2 + 2;
37963 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
37964 DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
37965 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
37966
37967#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
37968 if (js_ctx->flag_ext_custom)
37969#endif
37970#if defined(DUK_USE_JX)
37971 {
37972 *q++ = DUK_ASC_PIPE;
37973 q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q);
37974 *q++ = DUK_ASC_PIPE;
37975
37976 }
37977#endif
37978#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
37979 else
37980#endif
37981#if defined(DUK_USE_JC)
37982 {
37983 DUK_ASSERT(js_ctx->flag_ext_compatible);
37984 duk_memcpy((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
37985 q += 9;
37986 q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q);
37987 *q++ = DUK_ASC_DOUBLEQUOTE;
37988 *q++ = DUK_ASC_RCURLY;
37989 }
37990#endif
37991
37992 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
37993}
37994
37995DUK_LOCAL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
37996 duk__json_enc_buffer_data(js_ctx,
37997 (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
37998 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
37999}
38000#endif /* DUK_USE_JX || DUK_USE_JC */
38001
38002#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
38003DUK_LOCAL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
38004 duk_size_t i, n;
38005 const duk_uint8_t *buf;
38006 duk_uint8_t *q;
38007
38008 n = DUK_HBUFFER_GET_SIZE(h);
38009 if (n == 0) {
38010 DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY);
38011 return;
38012 }
38013
38014 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
38015
38016 /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18,
38017 * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack.
38018 *
38019 * Note that because the output buffer is reallocated from time to time,
38020 * side effects (such as finalizers) affecting the buffer 'h' must be
38021 * disabled. This is the case in the JSON.stringify() fast path.
38022 */
38023
38024 buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h);
38025 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38026 for (i = 0; i < n; i++) {
38027 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
38028 q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32);
38029 q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]);
38030 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
38031 }
38032 } else {
38033 q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw);
38034 for (i = 0; i < n; i++) {
38035 q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q);
38036 q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]);
38037 }
38038 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
38039 }
38040 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
38041
38042 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38043 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
38044 }
38045 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
38046}
38047#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
38048
38049#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38050DUK_LOCAL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
38051 char buf[64]; /* XXX: how to figure correct size? */
38052 const char *fmt;
38053
38054 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
38055 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
38056
38057 duk_memzero(buf, sizeof(buf));
38058
38059 /* The #if defined() clutter here needs to handle the three
38060 * cases: (1) JX+JC, (2) JX only, (3) JC only.
38061 */
38062#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
38063 if (js_ctx->flag_ext_custom)
38064#endif
38065#if defined(DUK_USE_JX)
38066 {
38067 fmt = ptr ? "(%p)" : "(null)";
38068 }
38069#endif
38070#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
38071 else
38072#endif
38073#if defined(DUK_USE_JC)
38074 {
38075 DUK_ASSERT(js_ctx->flag_ext_compatible);
38076 fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
38077 }
38078#endif
38079
38080 /* When ptr == NULL, the format argument is unused. */
38081 DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
38082 DUK__EMIT_CSTR(js_ctx, buf);
38083}
38084#endif /* DUK_USE_JX || DUK_USE_JC */
38085
38086#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
38087#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38088DUK_LOCAL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
38089 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
38090
38091 if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
38092 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
38093 } else {
38094 /* Handle both full and partial slice (as long as covered). */
38095 duk__json_enc_buffer_data(js_ctx,
38096 (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
38097 (duk_size_t) h_bufobj->length);
38098 }
38099}
38100#endif /* DUK_USE_JX || DUK_USE_JC */
38101#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
38102
38103/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
38104 * directly related to indent depth.
38105 */
38106#if defined(DUK_USE_PREFER_SIZE)
38107DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
38108 DUK_ASSERT(js_ctx->h_gap != NULL);
38109 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
38110
38111 DUK__EMIT_1(js_ctx, 0x0a);
38112 while (depth-- > 0) {
38113 DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
38114 }
38115}
38116#else /* DUK_USE_PREFER_SIZE */
38117DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
38118 const duk_uint8_t *gap_data;
38119 duk_size_t gap_len;
38120 duk_size_t avail_bytes; /* bytes of indent available for copying */
38121 duk_size_t need_bytes; /* bytes of indent still needed */
38122 duk_uint8_t *p_start;
38123 duk_uint8_t *p;
38124
38125 DUK_ASSERT(js_ctx->h_gap != NULL);
38126 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
38127
38128 DUK__EMIT_1(js_ctx, 0x0a);
38129 if (DUK_UNLIKELY(depth == 0)) {
38130 return;
38131 }
38132
38133 /* To handle deeper indents efficiently, make use of copies we've
38134 * already emitted. In effect we can emit a sequence of 1, 2, 4,
38135 * 8, etc copies, and then finish the last run. Byte counters
38136 * avoid multiply with gap_len on every loop.
38137 */
38138
38139 gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
38140 gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
38141 DUK_ASSERT(gap_len > 0);
38142
38143 need_bytes = gap_len * depth;
38144 p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
38145 p_start = p;
38146
38147 duk_memcpy((void *) p, (const void *) gap_data, (size_t) gap_len);
38148 p += gap_len;
38149 avail_bytes = gap_len;
38150 DUK_ASSERT(need_bytes >= gap_len);
38151 need_bytes -= gap_len;
38152
38153 while (need_bytes >= avail_bytes) {
38154 duk_memcpy((void *) p, (const void *) p_start, (size_t) avail_bytes);
38155 p += avail_bytes;
38156 need_bytes -= avail_bytes;
38157 avail_bytes <<= 1;
38158 }
38159
38160 DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
38161 duk_memcpy((void *) p, (const void *) p_start, (size_t) need_bytes);
38162 p += need_bytes;
38163 /*avail_bytes += need_bytes*/
38164
38165 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
38166}
38167#endif /* DUK_USE_PREFER_SIZE */
38168
38169/* Shared entry handling for object/array serialization. */
38170DUK_LOCAL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
38171 duk_hthread *thr = js_ctx->thr;
38172 duk_hobject *h_target;
38173 duk_uint_fast32_t i, n;
38174
38175 *entry_top = duk_get_top(thr);
38176
38177 duk_native_stack_check(thr);
38178 duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
38179
38180 /* Loop check using a hybrid approach: a fixed-size visited[] array
38181 * with overflow in a loop check object.
38182 */
38183
38184 h_target = duk_known_hobject(thr, -1); /* object or array */
38185
38186 n = js_ctx->recursion_depth;
38187 if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
38188 n = DUK_JSON_ENC_LOOPARRAY;
38189 }
38190 for (i = 0; i < n; i++) {
38191 if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
38192 DUK_DD(DUK_DDPRINT("slow path loop detect"));
38193 DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
38194 DUK_WO_NORETURN(return;);
38195 }
38196 }
38197 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
38198 js_ctx->visiting[js_ctx->recursion_depth] = h_target;
38199 } else {
38200 duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
38201 duk_dup_top(thr); /* -> [ ... voidp voidp ] */
38202 if (duk_has_prop(thr, js_ctx->idx_loop)) {
38203 DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
38204 DUK_WO_NORETURN(return;);
38205 }
38206 duk_push_true(thr); /* -> [ ... voidp true ] */
38207 duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
38208 }
38209
38210 /* C recursion check. */
38211
38212 DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
38213 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
38214 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
38215 DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT);
38216 DUK_WO_NORETURN(return;);
38217 }
38218 js_ctx->recursion_depth++;
38219
38220 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
38221 (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
38222}
38223
38224/* Shared exit handling for object/array serialization. */
38225DUK_LOCAL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
38226 duk_hthread *thr = js_ctx->thr;
38227 duk_hobject *h_target;
38228
38229 /* C recursion check. */
38230
38231 DUK_ASSERT(js_ctx->recursion_depth > 0);
38232 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
38233 js_ctx->recursion_depth--;
38234
38235 /* Loop check. */
38236
38237 h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */
38238
38239 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
38240 /* Previous entry was inside visited[], nothing to do. */
38241 } else {
38242 duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
38243 duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
38244 }
38245
38246 /* Restore stack top after unbalanced code paths. */
38247 duk_set_top(thr, *entry_top);
38248
38249 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
38250 (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
38251}
38252
38253/* The JO(value) operation: encode object.
38254 *
38255 * Stack policy: [ object ] -> [ object ].
38256 */
38257DUK_LOCAL void duk__json_enc_object(duk_json_enc_ctx *js_ctx) {
38258 duk_hthread *thr = js_ctx->thr;
38259 duk_hstring *h_key;
38260 duk_idx_t entry_top;
38261 duk_idx_t idx_obj;
38262 duk_idx_t idx_keys;
38263 duk_bool_t emitted;
38264 duk_uarridx_t arr_len, i;
38265 duk_size_t prev_size;
38266
38267 DUK_DDD(DUK_DDDPRINT("duk__json_enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
38268
38269 duk__json_enc_objarr_entry(js_ctx, &entry_top);
38270
38271 idx_obj = entry_top - 1;
38272
38273 if (js_ctx->idx_proplist >= 0) {
38274 idx_keys = js_ctx->idx_proplist;
38275 } else {
38276 /* XXX: would be nice to enumerate an object at specified index */
38277 duk_dup(thr, idx_obj);
38278 (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
38279 idx_keys = duk_require_normalize_index(thr, -1);
38280 /* leave stack unbalanced on purpose */
38281 }
38282
38283 DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
38284 (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys)));
38285
38286 /* Steps 8-10 have been merged to avoid a "partial" variable. */
38287
38288 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
38289
38290 /* XXX: keys is an internal object with all keys to be processed
38291 * in its (gapless) array part. Because nobody can touch the keys
38292 * object, we could iterate its array part directly (keeping in mind
38293 * that it can be reallocated).
38294 */
38295
38296 arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys);
38297 emitted = 0;
38298 for (i = 0; i < arr_len; i++) {
38299 duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */
38300
38301 DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
38302 (duk_tval *) duk_get_tval(thr, idx_obj),
38303 (duk_tval *) duk_get_tval(thr, -1)));
38304
38305 h_key = duk_known_hstring(thr, -1);
38306 DUK_ASSERT(h_key != NULL);
38307 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */
38308
38309 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
38310 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38311 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
38312 duk__json_enc_key_autoquote(js_ctx, h_key);
38313 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
38314 } else {
38315 duk__json_enc_key_autoquote(js_ctx, h_key);
38316 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
38317 }
38318
38319 /* [ ... key ] */
38320
38321 if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_obj) == 0)) {
38322 /* Value would yield 'undefined', so skip key altogether.
38323 * Side effects have already happened.
38324 */
38325 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
38326 } else {
38327 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
38328 emitted = 1;
38329 }
38330
38331 /* [ ... ] */
38332 }
38333
38334 if (emitted) {
38335 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
38336 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
38337 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38338 DUK_ASSERT(js_ctx->recursion_depth >= 1);
38339 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
38340 }
38341 }
38342 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
38343
38344 duk__json_enc_objarr_exit(js_ctx, &entry_top);
38345
38346 DUK_ASSERT_TOP(thr, entry_top);
38347}
38348
38349/* The JA(value) operation: encode array.
38350 *
38351 * Stack policy: [ array ] -> [ array ].
38352 */
38353DUK_LOCAL void duk__json_enc_array(duk_json_enc_ctx *js_ctx) {
38354 duk_hthread *thr = js_ctx->thr;
38355 duk_idx_t entry_top;
38356 duk_idx_t idx_arr;
38357 duk_bool_t emitted;
38358 duk_uarridx_t i, arr_len;
38359
38360 DUK_DDD(DUK_DDDPRINT("duk__json_enc_array: array=%!T",
38361 (duk_tval *) duk_get_tval(thr, -1)));
38362
38363 duk__json_enc_objarr_entry(js_ctx, &entry_top);
38364
38365 idx_arr = entry_top - 1;
38366
38367 /* Steps 8-10 have been merged to avoid a "partial" variable. */
38368
38369 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
38370
38371 arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr);
38372 emitted = 0;
38373 for (i = 0; i < arr_len; i++) {
38374 DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
38375 (duk_tval *) duk_get_tval(thr, idx_arr),
38376 (long) i, (long) arr_len));
38377
38378 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38379 DUK_ASSERT(js_ctx->recursion_depth >= 1);
38380 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
38381 }
38382
38383 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */
38384
38385 /* [ ... key ] */
38386
38387 if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_arr) == 0)) {
38388 /* Value would normally be omitted, replace with 'null'. */
38389 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
38390 } else {
38391 ;
38392 }
38393
38394 /* [ ... ] */
38395
38396 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
38397 emitted = 1;
38398 }
38399
38400 if (emitted) {
38401 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
38402 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
38403 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38404 DUK_ASSERT(js_ctx->recursion_depth >= 1);
38405 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
38406 }
38407 }
38408 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
38409
38410 duk__json_enc_objarr_exit(js_ctx, &entry_top);
38411
38412 DUK_ASSERT_TOP(thr, entry_top);
38413}
38414
38415/* The Str(key, holder) operation.
38416 *
38417 * Stack policy: [ ... key ] -> [ ... ]
38418 */
38419DUK_LOCAL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
38420 duk_hthread *thr = js_ctx->thr;
38421 duk_tval *tv;
38422 duk_tval *tv_holder;
38423 duk_tval *tv_key;
38424 duk_small_int_t c;
38425
38426 DUK_DDD(DUK_DDDPRINT("duk__json_enc_value: idx_holder=%ld, holder=%!T, key=%!T",
38427 (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
38428 (duk_tval *) duk_get_tval(thr, -1)));
38429
38430 tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder);
38431 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
38432 tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
38433 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
38434 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */
38435 (void) duk_hobject_getprop(thr, tv_holder, tv_key);
38436
38437 /* -> [ ... key val ] */
38438
38439 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
38440
38441 /* Standard JSON checks for .toJSON() only for actual objects; for
38442 * example, setting Number.prototype.toJSON and then serializing a
38443 * number won't invoke the .toJSON() method. However, lightfuncs and
38444 * plain buffers mimic objects so we check for their .toJSON() method.
38445 */
38446 if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
38447 DUK_TYPE_MASK_LIGHTFUNC |
38448 DUK_TYPE_MASK_BUFFER)) {
38449 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON);
38450 if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */
38451 DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
38452 /* XXX: duk_dup_unvalidated(thr, -2) etc. */
38453 duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */
38454 duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */
38455 duk_call_method(thr, 1); /* -> [ ... key val val' ] */
38456 duk_remove_m2(thr); /* -> [ ... key val' ] */
38457 } else {
38458 duk_pop(thr); /* -> [ ... key val ] */
38459 }
38460 }
38461
38462 /* [ ... key val ] */
38463
38464 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
38465
38466 if (js_ctx->h_replacer) {
38467 /* XXX: Here a "slice copy" would be useful. */
38468 DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
38469 duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
38470 duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */
38471 duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */
38472 duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */
38473 duk_call_method(thr, 2); /* -> [ ... key val val' ] */
38474 duk_remove_m2(thr); /* -> [ ... key val' ] */
38475 }
38476
38477 /* [ ... key val ] */
38478
38479 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
38480
38481 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
38482 if (DUK_TVAL_IS_OBJECT(tv)) {
38483 duk_hobject *h;
38484
38485 h = DUK_TVAL_GET_OBJECT(tv);
38486 DUK_ASSERT(h != NULL);
38487
38488#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
38489#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38490 if (DUK_HOBJECT_IS_BUFOBJ(h) &&
38491 js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) {
38492 /* With JX/JC a bufferobject gets serialized specially. */
38493 duk_hbufobj *h_bufobj;
38494 h_bufobj = (duk_hbufobj *) h;
38495 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
38496 duk__json_enc_bufobj(js_ctx, h_bufobj);
38497 goto pop2_emitted;
38498 }
38499 /* Otherwise bufferobjects get serialized as normal objects. */
38500#endif /* JX || JC */
38501#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
38502 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
38503 switch (c) {
38504 case DUK_HOBJECT_CLASS_NUMBER: {
38505 DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
38506 duk_to_number_m1(thr);
38507 /* The coercion potentially invokes user .valueOf() and .toString()
38508 * but can't result in a function value because ToPrimitive() would
38509 * reject such a result: test-dev-json-stringify-coercion-1.js.
38510 */
38511 DUK_ASSERT(!duk_is_callable(thr, -1));
38512 break;
38513 }
38514 case DUK_HOBJECT_CLASS_STRING: {
38515 DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
38516 duk_to_string(thr, -1);
38517 /* Same coercion behavior as for Number. */
38518 DUK_ASSERT(!duk_is_callable(thr, -1));
38519 break;
38520 }
38521#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38522 case DUK_HOBJECT_CLASS_POINTER:
38523#endif
38524 case DUK_HOBJECT_CLASS_BOOLEAN: {
38525 DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
38526 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
38527 duk_remove_m2(thr);
38528 break;
38529 }
38530 default: {
38531 /* Normal object which doesn't get automatically coerced to a
38532 * primitive value. Functions are checked for specially. The
38533 * primitive value coercions for Number, String, Pointer, and
38534 * Boolean can't result in functions so suffices to check here.
38535 * Symbol objects are handled like plain objects (their primitive
38536 * value is NOT looked up like for e.g. String objects).
38537 */
38538 DUK_ASSERT(h != NULL);
38539 if (DUK_HOBJECT_IS_CALLABLE(h)) {
38540#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38541 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
38542 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
38543 /* We only get here when doing non-standard JSON encoding */
38544 DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
38545 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
38546 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
38547 goto pop2_emitted;
38548 } else {
38549 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
38550 goto pop2_undef;
38551 }
38552#else /* DUK_USE_JX || DUK_USE_JC */
38553 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
38554 goto pop2_undef;
38555#endif /* DUK_USE_JX || DUK_USE_JC */
38556 }
38557 }
38558 } /* end switch */
38559 }
38560
38561 /* [ ... key val ] */
38562
38563 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
38564
38565 if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) {
38566 /* will result in undefined */
38567 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
38568 goto pop2_undef;
38569 }
38570 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
38571
38572 switch (DUK_TVAL_GET_TAG(tv)) {
38573#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38574 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
38575 case DUK_TAG_UNDEFINED: {
38576 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
38577 break;
38578 }
38579#endif
38580 case DUK_TAG_NULL: {
38581 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
38582 break;
38583 }
38584 case DUK_TAG_BOOLEAN: {
38585 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
38586 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
38587 break;
38588 }
38589#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38590 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
38591 case DUK_TAG_POINTER: {
38592 duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
38593 break;
38594 }
38595#endif /* DUK_USE_JX || DUK_USE_JC */
38596 case DUK_TAG_STRING: {
38597 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
38598 DUK_ASSERT(h != NULL);
38599 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
38600 goto pop2_undef;
38601 }
38602 duk__json_enc_quote_string(js_ctx, h);
38603 break;
38604 }
38605 case DUK_TAG_OBJECT: {
38606 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
38607 DUK_ASSERT(h != NULL);
38608
38609 /* Function values are handled completely above (including
38610 * coercion results):
38611 */
38612 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
38613
38614 if (duk_js_isarray_hobject(h)) {
38615 duk__json_enc_array(js_ctx);
38616 } else {
38617 duk__json_enc_object(js_ctx);
38618 }
38619 break;
38620 }
38621 /* Because plain buffers mimics Uint8Array, they have enumerable
38622 * index properties [0,byteLength[. Because JSON only serializes
38623 * enumerable own properties, no properties can be serialized for
38624 * plain buffers (all virtual properties are non-enumerable). However,
38625 * there may be a .toJSON() method which was already handled above.
38626 */
38627 case DUK_TAG_BUFFER: {
38628#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38629 if (js_ctx->flag_ext_custom_or_compatible) {
38630 duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
38631 break;
38632 }
38633#endif
38634
38635 /* Could implement a fastpath, but the fast path would need
38636 * to handle realloc side effects correctly.
38637 */
38638 duk_to_object(thr, -1);
38639 duk__json_enc_object(js_ctx);
38640 break;
38641 }
38642 case DUK_TAG_LIGHTFUNC: {
38643#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38644 /* We only get here when doing non-standard JSON encoding */
38645 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
38646 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
38647#else
38648 /* Standard JSON omits functions */
38649 DUK_UNREACHABLE();
38650#endif
38651 break;
38652 }
38653#if defined(DUK_USE_FASTINT)
38654 case DUK_TAG_FASTINT:
38655 /* Number serialization has a significant impact relative to
38656 * other fast path code, so careful fast path for fastints.
38657 */
38658 duk__json_enc_fastint_tval(js_ctx, tv);
38659 break;
38660#endif
38661 default: {
38662 /* number */
38663 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
38664 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
38665 /* XXX: A fast path for usual integers would be useful when
38666 * fastint support is not enabled.
38667 */
38668 duk__json_enc_double(js_ctx);
38669 break;
38670 }
38671 }
38672
38673#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38674 pop2_emitted:
38675#endif
38676 duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
38677 return 1; /* emitted */
38678
38679 pop2_undef:
38680 duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
38681 return 0; /* not emitted */
38682}
38683
38684/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
38685DUK_LOCAL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv) {
38686 duk_small_int_t c;
38687
38688 /* XXX: some kind of external internal type checker?
38689 * - type mask; symbol flag; class mask
38690 */
38691 DUK_ASSERT(tv != NULL);
38692 if (DUK_TVAL_IS_STRING(tv)) {
38693 duk_hstring *h;
38694 h = DUK_TVAL_GET_STRING(tv);
38695 DUK_ASSERT(h != NULL);
38696 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
38697 return 0;
38698 }
38699 return 1;
38700 } else if (DUK_TVAL_IS_NUMBER(tv)) {
38701 return 1;
38702 } else if (DUK_TVAL_IS_OBJECT(tv)) {
38703 duk_hobject *h;
38704 h = DUK_TVAL_GET_OBJECT(tv);
38705 DUK_ASSERT(h != NULL);
38706 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
38707 if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
38708 return 1;
38709 }
38710 }
38711
38712 return 0;
38713}
38714
38715/*
38716 * JSON.stringify() fast path
38717 *
38718 * Otherwise supports full JSON, JX, and JC features, but bails out on any
38719 * possible side effect which might change the value being serialized. The
38720 * fast path can take advantage of the fact that the value being serialized
38721 * is unchanged so that we can walk directly through property tables etc.
38722 */
38723
38724#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
38725DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
38726 duk_uint_fast32_t i, n;
38727
38728 DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
38729
38730 DUK_ASSERT(js_ctx != NULL);
38731 DUK_ASSERT(js_ctx->thr != NULL);
38732
38733#if 0 /* disabled for now */
38734 restart_match:
38735#endif
38736
38737 DUK_ASSERT(tv != NULL);
38738
38739 switch (DUK_TVAL_GET_TAG(tv)) {
38740 case DUK_TAG_UNDEFINED: {
38741#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38742 if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
38743 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
38744 break;
38745 } else {
38746 goto emit_undefined;
38747 }
38748#else
38749 goto emit_undefined;
38750#endif
38751 }
38752 case DUK_TAG_NULL: {
38753 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
38754 break;
38755 }
38756 case DUK_TAG_BOOLEAN: {
38757 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
38758 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
38759 break;
38760 }
38761 case DUK_TAG_STRING: {
38762 duk_hstring *h;
38763 h = DUK_TVAL_GET_STRING(tv);
38764 DUK_ASSERT(h != NULL);
38765 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
38766 goto emit_undefined;
38767 }
38768 duk__json_enc_quote_string(js_ctx, h);
38769 break;
38770 }
38771 case DUK_TAG_OBJECT: {
38772 duk_hobject *obj;
38773 duk_tval *tv_val;
38774 duk_bool_t emitted = 0;
38775 duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
38776 c_func, c_bufobj, c_object, c_abort;
38777
38778 /* For objects JSON.stringify() only looks for own, enumerable
38779 * properties which is nice for the fast path here.
38780 *
38781 * For arrays JSON.stringify() uses [[Get]] so it will actually
38782 * inherit properties during serialization! This fast path
38783 * supports gappy arrays as long as there's no actual inherited
38784 * property (which might be a getter etc).
38785 *
38786 * Since recursion only happens for objects, we can have both
38787 * recursion and loop checks here. We use a simple, depth-limited
38788 * loop check in the fast path because the object-based tracking
38789 * is very slow (when tested, it accounted for 50% of fast path
38790 * execution time for input data with a lot of small objects!).
38791 */
38792
38793 /* XXX: for real world code, could just ignore array inheritance
38794 * and only look at array own properties.
38795 */
38796
38797 /* We rely on a few object flag / class number relationships here,
38798 * assert for them.
38799 */
38800
38801 obj = DUK_TVAL_GET_OBJECT(tv);
38802 DUK_ASSERT(obj != NULL);
38803 DUK_HOBJECT_ASSERT_VALID(obj);
38804
38805 /* Once recursion depth is increased, exit path must decrease
38806 * it (though it's OK to abort the fast path).
38807 */
38808
38809 DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */
38810 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
38811 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
38812 DUK_DD(DUK_DDPRINT("fast path recursion limit"));
38813 DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_DEC_RECLIMIT);
38814 DUK_WO_NORETURN(return 0;);
38815 }
38816
38817 for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
38818 if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
38819 DUK_DD(DUK_DDPRINT("fast path loop detect"));
38820 DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
38821 DUK_WO_NORETURN(return 0;);
38822 }
38823 }
38824
38825 /* Guaranteed by recursion_limit setup so we don't have to
38826 * check twice.
38827 */
38828 DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
38829 js_ctx->visiting[js_ctx->recursion_depth] = obj;
38830 js_ctx->recursion_depth++;
38831
38832 /* If object has a .toJSON() property, we can't be certain
38833 * that it wouldn't mutate any value arbitrarily, so bail
38834 * out of the fast path.
38835 *
38836 * If an object is a Proxy we also can't avoid side effects
38837 * so abandon.
38838 */
38839 /* XXX: non-callable .toJSON() doesn't need to cause an abort
38840 * but does at the moment, probably not worth fixing.
38841 */
38842 if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
38843 DUK_HOBJECT_IS_PROXY(obj)) {
38844 DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
38845 goto abort_fastpath;
38846 }
38847
38848 /* We could use a switch-case for the class number but it turns out
38849 * a small if-else ladder on class masks is better. The if-ladder
38850 * should be in order of relevancy.
38851 */
38852
38853 /* XXX: move masks to js_ctx? they don't change during one
38854 * fast path invocation.
38855 */
38856 DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
38857#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
38858 if (js_ctx->flag_ext_custom_or_compatible) {
38859 c_all = DUK_HOBJECT_CMASK_ALL;
38860 c_array = DUK_HOBJECT_CMASK_ARRAY;
38861 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
38862 DUK_HOBJECT_CMASK_STRING |
38863 DUK_HOBJECT_CMASK_BOOLEAN |
38864 DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */
38865 c_func = DUK_HOBJECT_CMASK_FUNCTION;
38866 c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
38867 c_undef = 0;
38868 c_abort = 0;
38869 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
38870 }
38871 else
38872#endif
38873 {
38874 c_all = DUK_HOBJECT_CMASK_ALL;
38875 c_array = DUK_HOBJECT_CMASK_ARRAY;
38876 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
38877 DUK_HOBJECT_CMASK_STRING |
38878 DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */
38879 c_func = 0;
38880 c_bufobj = 0;
38881 c_undef = DUK_HOBJECT_CMASK_FUNCTION |
38882 DUK_HOBJECT_CMASK_POINTER;
38883 /* As the fast path doesn't currently properly support
38884 * duk_hbufobj virtual properties, abort fast path if
38885 * we encounter them in plain JSON mode.
38886 */
38887 c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
38888 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
38889 }
38890
38891 c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj);
38892 if (c_bit & c_object) {
38893 /* All other object types. */
38894 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
38895
38896 /* A non-Array object should not have an array part in practice.
38897 * But since it is supported internally (and perhaps used at some
38898 * point), check and abandon if that's the case.
38899 */
38900 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
38901 DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
38902 goto abort_fastpath;
38903 }
38904
38905 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
38906 duk_hstring *k;
38907 duk_size_t prev_size;
38908
38909 k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
38910 if (!k) {
38911 continue;
38912 }
38913 if (DUK_HSTRING_HAS_ARRIDX(k)) {
38914 /* If an object has array index keys we would need
38915 * to sort them into the ES2015 enumeration order to
38916 * be consistent with the slow path. Abort the fast
38917 * path and handle in the slow path for now.
38918 */
38919 DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path"));
38920 goto abort_fastpath;
38921 }
38922 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
38923 continue;
38924 }
38925 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
38926 /* Getter might have arbitrary side effects,
38927 * so bail out.
38928 */
38929 DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
38930 goto abort_fastpath;
38931 }
38932 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
38933 continue;
38934 }
38935
38936 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
38937
38938 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
38939 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38940 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
38941 duk__json_enc_key_autoquote(js_ctx, k);
38942 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
38943 } else {
38944 duk__json_enc_key_autoquote(js_ctx, k);
38945 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
38946 }
38947
38948 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
38949 DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
38950 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
38951 } else {
38952 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
38953 emitted = 1;
38954 }
38955 }
38956
38957 /* If any non-Array value had enumerable virtual own
38958 * properties, they should be serialized here (actually,
38959 * before the explicit properties). Standard types don't.
38960 */
38961
38962 if (emitted) {
38963 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
38964 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
38965 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38966 DUK_ASSERT(js_ctx->recursion_depth >= 1);
38967 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
38968 }
38969 }
38970 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
38971 } else if (c_bit & c_array) {
38972 duk_uint_fast32_t arr_len;
38973 duk_uint_fast32_t asize;
38974
38975 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
38976
38977 /* Assume arrays are dense in the fast path. */
38978 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
38979 DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
38980 goto abort_fastpath;
38981 }
38982
38983 arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
38984 asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
38985 /* Array part may be larger than 'length'; if so, iterate
38986 * only up to array 'length'. Array part may also be smaller
38987 * than 'length' in some cases.
38988 */
38989 for (i = 0; i < arr_len; i++) {
38990 duk_tval *tv_arrval;
38991 duk_hstring *h_tmp;
38992 duk_bool_t has_inherited;
38993
38994 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
38995 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth);
38996 }
38997
38998 if (DUK_LIKELY(i < asize)) {
38999 tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
39000 if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) {
39001 /* Expected case: element is present. */
39002 if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) {
39003 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
39004 }
39005 goto elem_done;
39006 }
39007 }
39008
39009 /* Gap in array; check for inherited property,
39010 * bail out if one exists. This should be enough
39011 * to support gappy arrays for all practical code.
39012 */
39013
39014 h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i);
39015 has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
39016 duk_pop(js_ctx->thr);
39017 if (has_inherited) {
39018 DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
39019 goto abort_fastpath;
39020 }
39021
39022 /* Ordinary gap, undefined encodes to 'null' in
39023 * standard JSON, but JX/JC use their form for
39024 * undefined to better preserve the typing.
39025 */
39026 DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
39027#if defined(DUK_USE_JX)
39028 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
39029#else
39030 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
39031#endif
39032 /* fall through */
39033
39034 elem_done:
39035 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
39036 emitted = 1;
39037 }
39038
39039 if (emitted) {
39040 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
39041 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
39042 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
39043 DUK_ASSERT(js_ctx->recursion_depth >= 1);
39044 duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
39045 }
39046 }
39047 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
39048 } else if (c_bit & c_unbox) {
39049 /* Certain boxed types are required to go through
39050 * automatic unboxing. Rely on internal value being
39051 * sane (to avoid infinite recursion).
39052 */
39053 DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */
39054
39055#if 1
39056 /* The code below is incorrect if .toString() or .valueOf() have
39057 * have been overridden. The correct approach would be to look up
39058 * the method(s) and if they resolve to the built-in function we
39059 * can safely bypass it and look up the internal value directly.
39060 * Unimplemented for now, abort fast path for boxed values.
39061 */
39062 goto abort_fastpath;
39063#else /* disabled */
39064 /* Disabled until fixed, see above. */
39065 duk_tval *tv_internal;
39066
39067 DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
39068
39069 tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
39070 DUK_ASSERT(tv_internal != NULL);
39071 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
39072 DUK_TVAL_IS_NUMBER(tv_internal) ||
39073 DUK_TVAL_IS_BOOLEAN(tv_internal) ||
39074 DUK_TVAL_IS_POINTER(tv_internal));
39075
39076 tv = tv_internal;
39077 DUK_ASSERT(js_ctx->recursion_depth > 0);
39078 js_ctx->recursion_depth--; /* required to keep recursion depth correct */
39079 goto restart_match;
39080#endif /* disabled */
39081#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39082 } else if (c_bit & c_func) {
39083 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
39084#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
39085 } else if (c_bit & c_bufobj) {
39086 duk__json_enc_bufobj(js_ctx, (duk_hbufobj *) obj);
39087#endif
39088#endif
39089 } else if (c_bit & c_abort) {
39090 DUK_DD(DUK_DDPRINT("abort fast path for unsupported type"));
39091 goto abort_fastpath;
39092 } else {
39093 DUK_ASSERT((c_bit & c_undef) != 0);
39094
39095 /* Must decrease recursion depth before returning. */
39096 DUK_ASSERT(js_ctx->recursion_depth > 0);
39097 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
39098 js_ctx->recursion_depth--;
39099 goto emit_undefined;
39100 }
39101
39102 DUK_ASSERT(js_ctx->recursion_depth > 0);
39103 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
39104 js_ctx->recursion_depth--;
39105 break;
39106 }
39107 case DUK_TAG_BUFFER: {
39108 /* Plain buffers are treated like Uint8Arrays: they have
39109 * enumerable indices. Other virtual properties are not
39110 * enumerable, and inherited properties are not serialized.
39111 * However, there can be a replacer (not relevant here) or
39112 * a .toJSON() method (which we need to check for explicitly).
39113 */
39114
39115#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
39116 if (duk_hobject_hasprop_raw(js_ctx->thr,
39117 js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE],
39118 DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) {
39119 DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path"));
39120 goto abort_fastpath;
39121 }
39122#endif
39123
39124#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39125 if (js_ctx->flag_ext_custom_or_compatible) {
39126 duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
39127 break;
39128 }
39129#endif
39130
39131 /* Plain buffers mimic Uint8Arrays, and have enumerable index
39132 * properties.
39133 */
39134 duk__json_enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
39135 break;
39136 }
39137 case DUK_TAG_POINTER: {
39138#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39139 if (js_ctx->flag_ext_custom_or_compatible) {
39140 duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
39141 break;
39142 } else {
39143 goto emit_undefined;
39144 }
39145#else
39146 goto emit_undefined;
39147#endif
39148 }
39149 case DUK_TAG_LIGHTFUNC: {
39150 /* A lightfunc might also inherit a .toJSON() so just bail out. */
39151 /* XXX: Could just lookup .toJSON() and continue in fast path,
39152 * as it would almost never be defined.
39153 */
39154 DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
39155 goto abort_fastpath;
39156 }
39157#if defined(DUK_USE_FASTINT)
39158 case DUK_TAG_FASTINT: {
39159 /* Number serialization has a significant impact relative to
39160 * other fast path code, so careful fast path for fastints.
39161 */
39162 duk__json_enc_fastint_tval(js_ctx, tv);
39163 break;
39164 }
39165#endif
39166 default: {
39167 /* XXX: A fast path for usual integers would be useful when
39168 * fastint support is not enabled.
39169 */
39170 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
39171 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
39172
39173 /* XXX: Stack discipline is annoying, could be changed in numconv. */
39174 duk_push_tval(js_ctx->thr, tv);
39175 duk__json_enc_double(js_ctx);
39176 duk_pop(js_ctx->thr);
39177
39178#if 0
39179 /* Could also rely on native sprintf(), but it will handle
39180 * values like NaN, Infinity, -0, exponent notation etc in
39181 * a JSON-incompatible way.
39182 */
39183 duk_double_t d;
39184 char buf[64];
39185
39186 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
39187 d = DUK_TVAL_GET_DOUBLE(tv);
39188 DUK_SPRINTF(buf, "%lg", d);
39189 DUK__EMIT_CSTR(js_ctx, buf);
39190#endif
39191 }
39192 }
39193 return 1; /* not undefined */
39194
39195 emit_undefined:
39196 return 0; /* value was undefined/unsupported */
39197
39198 abort_fastpath:
39199 /* Error message doesn't matter: the error is ignored anyway. */
39200 DUK_DD(DUK_DDPRINT("aborting fast path"));
39201 DUK_ERROR_INTERNAL(js_ctx->thr);
39202 DUK_WO_NORETURN(return 0;);
39203}
39204
39205DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
39206 duk_json_enc_ctx *js_ctx;
39207 duk_tval *tv;
39208
39209 DUK_ASSERT(thr != NULL);
39210 DUK_ASSERT(udata != NULL);
39211
39212 js_ctx = (duk_json_enc_ctx *) udata;
39213 DUK_ASSERT(js_ctx != NULL);
39214
39215 tv = DUK_GET_TVAL_NEGIDX(thr, -1);
39216 if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
39217 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
39218 DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */
39219 }
39220
39221 return 0;
39222}
39223#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
39224
39225/*
39226 * Top level wrappers
39227 */
39228
39229DUK_INTERNAL
39230void duk_bi_json_parse_helper(duk_hthread *thr,
39231 duk_idx_t idx_value,
39232 duk_idx_t idx_reviver,
39233 duk_small_uint_t flags) {
39234 duk_json_dec_ctx js_ctx_alloc;
39235 duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
39236 duk_hstring *h_text;
39237#if defined(DUK_USE_ASSERTIONS)
39238 duk_idx_t entry_top = duk_get_top(thr);
39239#endif
39240
39241 /* negative top-relative indices not allowed now */
39242 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
39243 DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
39244
39245 DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
39246 (duk_tval *) duk_get_tval(thr, idx_value),
39247 (duk_tval *) duk_get_tval(thr, idx_reviver),
39248 (unsigned long) flags,
39249 (long) duk_get_top(thr)));
39250
39251 duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
39252 js_ctx->thr = thr;
39253#if defined(DUK_USE_EXPLICIT_NULL_INIT)
39254 /* nothing now */
39255#endif
39256 js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
39257 DUK_ASSERT(js_ctx->recursion_depth == 0);
39258
39259 /* Flag handling currently assumes that flags are consistent. This is OK
39260 * because the call sites are now strictly controlled.
39261 */
39262
39263 js_ctx->flags = flags;
39264#if defined(DUK_USE_JX)
39265 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
39266#endif
39267#if defined(DUK_USE_JC)
39268 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
39269#endif
39270#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39271 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
39272#endif
39273
39274 h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */
39275 DUK_ASSERT(h_text != NULL);
39276
39277 /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
39278 * valid and points to the string NUL terminator (which is always
39279 * guaranteed for duk_hstrings.
39280 */
39281 js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
39282 js_ctx->p = js_ctx->p_start;
39283 js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
39284 DUK_HSTRING_GET_BYTELEN(h_text);
39285 DUK_ASSERT(*(js_ctx->p_end) == 0x00);
39286
39287 duk__json_dec_value(js_ctx); /* -> [ ... value ] */
39288 DUK_ASSERT(js_ctx->recursion_depth == 0);
39289
39290 /* Trailing whitespace has been eaten by duk__json_dec_value(), so if
39291 * we're not at end of input here, it's a SyntaxError.
39292 */
39293
39294 if (js_ctx->p != js_ctx->p_end) {
39295 duk__json_dec_syntax_error(js_ctx);
39296 }
39297
39298 if (duk_is_callable(thr, idx_reviver)) {
39299 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
39300 (duk_tval *) duk_get_tval(thr, idx_reviver)));
39301
39302 js_ctx->idx_reviver = idx_reviver;
39303
39304 duk_push_object(thr);
39305 duk_dup_m2(thr); /* -> [ ... val root val ] */
39306 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
39307 duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
39308
39309 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
39310 (duk_tval *) duk_get_tval(thr, -2),
39311 (duk_tval *) duk_get_tval(thr, -1)));
39312
39313 DUK_ASSERT(js_ctx->recursion_depth == 0);
39314 duk__json_dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
39315 DUK_ASSERT(js_ctx->recursion_depth == 0);
39316 duk_remove_m2(thr); /* -> [ ... val' ] */
39317 } else {
39318 DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
39319 (duk_tval *) duk_get_tval(thr, idx_reviver)));
39320 }
39321
39322 /* Final result is at stack top. */
39323
39324 DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
39325 (duk_tval *) duk_get_tval(thr, idx_value),
39326 (duk_tval *) duk_get_tval(thr, idx_reviver),
39327 (unsigned long) flags,
39328 (duk_tval *) duk_get_tval(thr, -1),
39329 (long) duk_get_top(thr)));
39330
39331 DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
39332}
39333
39334DUK_INTERNAL
39335void duk_bi_json_stringify_helper(duk_hthread *thr,
39336 duk_idx_t idx_value,
39337 duk_idx_t idx_replacer,
39338 duk_idx_t idx_space,
39339 duk_small_uint_t flags) {
39340 duk_json_enc_ctx js_ctx_alloc;
39341 duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
39342 duk_hobject *h;
39343 duk_idx_t idx_holder;
39344 duk_idx_t entry_top;
39345
39346 /* negative top-relative indices not allowed now */
39347 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
39348 DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
39349 DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
39350
39351 DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
39352 (duk_tval *) duk_get_tval(thr, idx_value),
39353 (duk_tval *) duk_get_tval(thr, idx_replacer),
39354 (duk_tval *) duk_get_tval(thr, idx_space),
39355 (unsigned long) flags,
39356 (long) duk_get_top(thr)));
39357
39358 entry_top = duk_get_top(thr);
39359
39360 /*
39361 * Context init
39362 */
39363
39364 duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
39365 js_ctx->thr = thr;
39366#if defined(DUK_USE_EXPLICIT_NULL_INIT)
39367 js_ctx->h_replacer = NULL;
39368 js_ctx->h_gap = NULL;
39369#endif
39370 js_ctx->idx_proplist = -1;
39371
39372 /* Flag handling currently assumes that flags are consistent. This is OK
39373 * because the call sites are now strictly controlled.
39374 */
39375
39376 js_ctx->flags = flags;
39377 js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
39378 js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
39379#if defined(DUK_USE_JX)
39380 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
39381#endif
39382#if defined(DUK_USE_JC)
39383 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
39384#endif
39385#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39386 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
39387#endif
39388
39389 /* The #if defined() clutter here handles the JX/JC enable/disable
39390 * combinations properly.
39391 */
39392#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39393 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
39394#if defined(DUK_USE_JX)
39395 if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
39396 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
39397 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
39398 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
39399 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
39400 js_ctx->stridx_custom_function =
39401 (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
39402 DUK_STRIDX_JSON_EXT_FUNCTION2 :
39403 DUK_STRIDX_JSON_EXT_FUNCTION1;
39404 }
39405#endif /* DUK_USE_JX */
39406#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
39407 else
39408#endif /* DUK_USE_JX && DUK_USE_JC */
39409#if defined(DUK_USE_JC)
39410 if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
39411 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
39412 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
39413 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
39414 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
39415 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
39416 }
39417#endif /* DUK_USE_JC */
39418#endif /* DUK_USE_JX || DUK_USE_JC */
39419
39420#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
39421 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
39422 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
39423 DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
39424 }
39425 else
39426#endif /* DUK_USE_JX || DUK_USE_JC */
39427 {
39428 /* Plain buffer is treated like ArrayBuffer and serialized.
39429 * Lightfuncs are treated like objects, but JSON explicitly
39430 * skips serializing Function objects so we can just reject
39431 * lightfuncs here.
39432 */
39433 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
39434 DUK_TYPE_MASK_POINTER |
39435 DUK_TYPE_MASK_LIGHTFUNC;
39436 }
39437
39438 DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
39439
39440 js_ctx->idx_loop = duk_push_bare_object(thr);
39441 DUK_ASSERT(js_ctx->idx_loop >= 0);
39442
39443 /* [ ... buf loop ] */
39444
39445 /*
39446 * Process replacer/proplist (2nd argument to JSON.stringify)
39447 */
39448
39449 h = duk_get_hobject(thr, idx_replacer);
39450 if (h != NULL) {
39451 if (DUK_HOBJECT_IS_CALLABLE(h)) {
39452 js_ctx->h_replacer = h;
39453 } else if (duk_js_isarray_hobject(h)) {
39454 /* Here the specification requires correct array index enumeration
39455 * which is a bit tricky for sparse arrays (it is handled by the
39456 * enum setup code). We now enumerate ancestors too, although the
39457 * specification is not very clear on whether that is required.
39458 */
39459
39460 duk_uarridx_t plist_idx = 0;
39461 duk_small_uint_t enum_flags;
39462
39463 js_ctx->idx_proplist = duk_push_bare_array(thr);
39464
39465 enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
39466 DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
39467 duk_enum(thr, idx_replacer, enum_flags);
39468 while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
39469 /* [ ... proplist enum_obj key val ] */
39470 if (duk__json_enc_allow_into_proplist(duk_get_tval(thr, -1))) {
39471 /* XXX: duplicates should be eliminated here */
39472 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
39473 (duk_tval *) duk_get_tval(thr, -2),
39474 (duk_tval *) duk_get_tval(thr, -1)));
39475 duk_to_string(thr, -1); /* extra coercion of strings is OK */
39476 duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
39477 plist_idx++;
39478 duk_pop(thr);
39479 } else {
39480 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
39481 (duk_tval *) duk_get_tval(thr, -2),
39482 (duk_tval *) duk_get_tval(thr, -1)));
39483 duk_pop_2(thr);
39484 }
39485 }
39486 duk_pop(thr); /* pop enum */
39487
39488 /* [ ... proplist ] */
39489 }
39490 }
39491
39492 /* [ ... buf loop (proplist) ] */
39493
39494 /*
39495 * Process space (3rd argument to JSON.stringify)
39496 */
39497
39498 h = duk_get_hobject(thr, idx_space);
39499 if (h != NULL) {
39500 duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
39501 if (c == DUK_HOBJECT_CLASS_NUMBER) {
39502 duk_to_number(thr, idx_space);
39503 } else if (c == DUK_HOBJECT_CLASS_STRING) {
39504 duk_to_string(thr, idx_space);
39505 }
39506 }
39507
39508 if (duk_is_number(thr, idx_space)) {
39509 duk_small_int_t nspace;
39510 /* spaces[] must be static to allow initializer with old compilers like BCC */
39511 static const char spaces[10] = {
39512 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
39513 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
39514 DUK_ASC_SPACE, DUK_ASC_SPACE
39515 }; /* XXX: helper */
39516
39517 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
39518 nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/);
39519 DUK_ASSERT(nspace >= 0 && nspace <= 10);
39520
39521 duk_push_lstring(thr, spaces, (duk_size_t) nspace);
39522 js_ctx->h_gap = duk_known_hstring(thr, -1);
39523 DUK_ASSERT(js_ctx->h_gap != NULL);
39524 } else if (duk_is_string_notsymbol(thr, idx_space)) {
39525 duk_dup(thr, idx_space);
39526 duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */
39527 js_ctx->h_gap = duk_known_hstring(thr, -1);
39528 } else {
39529 /* nop */
39530 }
39531
39532 if (js_ctx->h_gap != NULL) {
39533 /* If gap is empty, behave as if not given at all. Check
39534 * against byte length because character length is more
39535 * expensive.
39536 */
39537 if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) {
39538 js_ctx->h_gap = NULL;
39539 }
39540 }
39541
39542 /* [ ... buf loop (proplist) (gap) ] */
39543
39544 /*
39545 * Fast path: assume no mutation, iterate object property tables
39546 * directly; bail out if that assumption doesn't hold.
39547 */
39548
39549#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
39550 if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
39551 js_ctx->idx_proplist == -1) { /* proplist is very rare */
39552 duk_int_t pcall_rc;
39553 duk_small_uint_t prev_ms_base_flags;
39554
39555 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
39556
39557 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
39558 * array so we don't need two counter checks in the fast path. The
39559 * slow path has a much larger recursion limit which we'll use if
39560 * necessary.
39561 */
39562 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
39563 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
39564 DUK_ASSERT(js_ctx->recursion_depth == 0);
39565
39566 /* Execute the fast path in a protected call. If any error is thrown,
39567 * fall back to the slow path. This includes e.g. recursion limit
39568 * because the fast path has a smaller recursion limit (and simpler,
39569 * limited loop detection).
39570 */
39571
39572 duk_dup(thr, idx_value);
39573
39574 /* Must prevent finalizers which may have arbitrary side effects. */
39575 prev_ms_base_flags = thr->heap->ms_base_flags;
39576 thr->heap->ms_base_flags |=
39577 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */
39578 thr->heap->pf_prevent_count++; /* Prevent finalizers. */
39579 DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
39580
39581 pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
39582
39583 DUK_ASSERT(thr->heap->pf_prevent_count > 0);
39584 thr->heap->pf_prevent_count--;
39585 thr->heap->ms_base_flags = prev_ms_base_flags;
39586
39587 if (pcall_rc == DUK_EXEC_SUCCESS) {
39588 DUK_DD(DUK_DDPRINT("fast path successful"));
39589 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
39590 goto replace_finished;
39591 }
39592
39593 /* We come here for actual aborts (like encountering .toJSON())
39594 * but also for recursion/loop errors. Bufwriter size can be
39595 * kept because we'll probably need at least as much as we've
39596 * allocated so far.
39597 */
39598 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
39599 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
39600 js_ctx->recursion_depth = 0;
39601 }
39602#endif
39603
39604 /*
39605 * Create wrapper object and serialize
39606 */
39607
39608 idx_holder = duk_push_object(thr);
39609 duk_dup(thr, idx_value);
39610 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);
39611
39612 DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
39613 "proplist=%!T, gap=%!O, holder=%!T",
39614 (unsigned long) js_ctx->flags,
39615 (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
39616 (duk_heaphdr *) js_ctx->h_replacer,
39617 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
39618 (duk_heaphdr *) js_ctx->h_gap,
39619 (duk_tval *) duk_get_tval(thr, -1)));
39620
39621 /* serialize the wrapper with empty string key */
39622
39623 duk_push_hstring_empty(thr);
39624
39625 /* [ ... buf loop (proplist) (gap) holder "" ] */
39626
39627 js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
39628 DUK_ASSERT(js_ctx->recursion_depth == 0);
39629
39630 if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
39631 /* Result is undefined. */
39632 duk_push_undefined(thr);
39633 } else {
39634 /* Convert buffer to result string. */
39635 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
39636 }
39637
39638 DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
39639 "proplist=%!T, gap=%!O, holder=%!T",
39640 (unsigned long) js_ctx->flags,
39641 (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
39642 (duk_heaphdr *) js_ctx->h_replacer,
39643 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
39644 (duk_heaphdr *) js_ctx->h_gap,
39645 (duk_tval *) duk_get_tval(thr, idx_holder)));
39646
39647 /* The stack has a variable shape here, so force it to the
39648 * desired one explicitly.
39649 */
39650
39651#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
39652 replace_finished:
39653#endif
39654 duk_replace(thr, entry_top);
39655 duk_set_top(thr, entry_top + 1);
39656
39657 DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
39658 "flags=0x%08lx, result=%!T, stack_top=%ld",
39659 (duk_tval *) duk_get_tval(thr, idx_value),
39660 (duk_tval *) duk_get_tval(thr, idx_replacer),
39661 (duk_tval *) duk_get_tval(thr, idx_space),
39662 (unsigned long) flags,
39663 (duk_tval *) duk_get_tval(thr, -1),
39664 (long) duk_get_top(thr)));
39665
39666 DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
39667}
39668
39669#if defined(DUK_USE_JSON_BUILTIN)
39670
39671/*
39672 * Entry points
39673 */
39674
39675DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) {
39676 duk_bi_json_parse_helper(thr,
39677 0 /*idx_value*/,
39678 1 /*idx_replacer*/,
39679 0 /*flags*/);
39680 return 1;
39681}
39682
39683DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) {
39684 duk_bi_json_stringify_helper(thr,
39685 0 /*idx_value*/,
39686 1 /*idx_replacer*/,
39687 2 /*idx_space*/,
39688 0 /*flags*/);
39689 return 1;
39690}
39691
39692#endif /* DUK_USE_JSON_BUILTIN */
39693
39694#endif /* DUK_USE_JSON_SUPPORT */
39695
39696/* automatic undefs */
39697#undef DUK__EMIT_1
39698#undef DUK__EMIT_2
39699#undef DUK__EMIT_CSTR
39700#undef DUK__EMIT_HSTR
39701#undef DUK__EMIT_STRIDX
39702#undef DUK__JSON_DECSTR_BUFSIZE
39703#undef DUK__JSON_DECSTR_CHUNKSIZE
39704#undef DUK__JSON_ENCSTR_CHUNKSIZE
39705#undef DUK__JSON_MAX_ESC_LEN
39706#undef DUK__JSON_STRINGIFY_BUFSIZE
39707#undef DUK__MKESC
39708#undef DUK__UNEMIT_1
39709#line 1 "duk_bi_math.c"
39710/*
39711 * Math built-ins
39712 */
39713
39714/* #include duk_internal.h -> already included */
39715
39716#if defined(DUK_USE_MATH_BUILTIN)
39717
39718/*
39719 * Use static helpers which can work with math.h functions matching
39720 * the following signatures. This is not portable if any of these math
39721 * functions is actually a macro.
39722 *
39723 * Typing here is intentionally 'double' wherever values interact with
39724 * the standard library APIs.
39725 */
39726
39727typedef double (*duk__one_arg_func)(double);
39728typedef double (*duk__two_arg_func)(double, double);
39729
39730DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) {
39731 duk_idx_t n = duk_get_top(thr);
39732 duk_idx_t i;
39733 duk_double_t res = initial;
39734 duk_double_t t;
39735
39736 /*
39737 * Note: fmax() does not match the E5 semantics. E5 requires
39738 * that if -any- input to Math.max() is a NaN, the result is a
39739 * NaN. fmax() will return a NaN only if -both- inputs are NaN.
39740 * Same applies to fmin().
39741 *
39742 * Note: every input value must be coerced with ToNumber(), even
39743 * if we know the result will be a NaN anyway: ToNumber() may have
39744 * side effects for which even order of evaluation matters.
39745 */
39746
39747 for (i = 0; i < n; i++) {
39748 t = duk_to_number(thr, i);
39749 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
39750 /* Note: not normalized, but duk_push_number() will normalize */
39751 res = (duk_double_t) DUK_DOUBLE_NAN;
39752 } else {
39753 res = (duk_double_t) min_max(res, (double) t);
39754 }
39755 }
39756
39757 duk_push_number(thr, res);
39758 return 1;
39759}
39760
39761DUK_LOCAL double duk__fmin_fixed(double x, double y) {
39762 /* fmin() with args -0 and +0 is not guaranteed to return
39763 * -0 as ECMAScript requires.
39764 */
39765 if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) {
39766 duk_double_union du1, du2;
39767 du1.d = x;
39768 du2.d = y;
39769
39770 /* Already checked to be zero so these must hold, and allow us
39771 * to check for "x is -0 or y is -0" by ORing the high parts
39772 * for comparison.
39773 */
39774 DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
39775 DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
39776
39777 /* XXX: what's the safest way of creating a negative zero? */
39778 if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) {
39779 /* Enter here if either x or y (or both) is -0. */
39780 return -0.0;
39781 } else {
39782 return +0.0;
39783 }
39784 }
39785 return duk_double_fmin(x, y);
39786}
39787
39788DUK_LOCAL double duk__fmax_fixed(double x, double y) {
39789 /* fmax() with args -0 and +0 is not guaranteed to return
39790 * +0 as ECMAScript requires.
39791 */
39792 if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) {
39793 if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
39794 return +0.0;
39795 } else {
39796 return -0.0;
39797 }
39798 }
39799 return duk_double_fmax(x, y);
39800}
39801
39802#if defined(DUK_USE_ES6)
39803DUK_LOCAL double duk__cbrt(double x) {
39804 /* cbrt() is C99. To avoid hassling embedders with the need to provide a
39805 * cube root function, we can get by with pow(). The result is not
39806 * identical, but that's OK: ES2015 says it's implementation-dependent.
39807 */
39808
39809#if defined(DUK_CBRT)
39810 /* cbrt() matches ES2015 requirements. */
39811 return DUK_CBRT(x);
39812#else
39813 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
39814
39815 /* pow() does not, however. */
39816 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
39817 return x;
39818 }
39819 if (DUK_SIGNBIT(x)) {
39820 return -DUK_POW(-x, 1.0 / 3.0);
39821 } else {
39822 return DUK_POW(x, 1.0 / 3.0);
39823 }
39824#endif
39825}
39826
39827DUK_LOCAL double duk__log2(double x) {
39828#if defined(DUK_LOG2)
39829 return DUK_LOG2(x);
39830#else
39831 return DUK_LOG(x) * DUK_DOUBLE_LOG2E;
39832#endif
39833}
39834
39835DUK_LOCAL double duk__log10(double x) {
39836#if defined(DUK_LOG10)
39837 return DUK_LOG10(x);
39838#else
39839 return DUK_LOG(x) * DUK_DOUBLE_LOG10E;
39840#endif
39841}
39842
39843DUK_LOCAL double duk__trunc(double x) {
39844#if defined(DUK_TRUNC)
39845 return DUK_TRUNC(x);
39846#else
39847 /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor()
39848 * is required to return -0 when the argument is -0.
39849 */
39850 return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x);
39851#endif
39852}
39853#endif /* DUK_USE_ES6 */
39854
39855DUK_LOCAL double duk__round_fixed(double x) {
39856 /* Numbers half-way between integers must be rounded towards +Infinity,
39857 * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
39858 * sign must be set appropriately. E5.1 Section 15.8.2.15.
39859 *
39860 * Note that ANSI C round() is "round to nearest integer, away from zero",
39861 * which is incorrect for negative values. Here we make do with floor().
39862 */
39863
39864 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
39865 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
39866 return x;
39867 }
39868
39869 /*
39870 * x is finite and non-zero
39871 *
39872 * -1.6 -> floor(-1.1) -> -2
39873 * -1.5 -> floor(-1.0) -> -1 (towards +Inf)
39874 * -1.4 -> floor(-0.9) -> -1
39875 * -0.5 -> -0.0 (special case)
39876 * -0.1 -> -0.0 (special case)
39877 * +0.1 -> +0.0 (special case)
39878 * +0.5 -> floor(+1.0) -> 1 (towards +Inf)
39879 * +1.4 -> floor(+1.9) -> 1
39880 * +1.5 -> floor(+2.0) -> 2 (towards +Inf)
39881 * +1.6 -> floor(+2.1) -> 2
39882 */
39883
39884 if (x >= -0.5 && x < 0.5) {
39885 /* +0.5 is handled by floor, this is on purpose */
39886 if (x < 0.0) {
39887 return -0.0;
39888 } else {
39889 return +0.0;
39890 }
39891 }
39892
39893 return DUK_FLOOR(x + 0.5);
39894}
39895
39896/* Wrappers for calling standard math library methods. These may be required
39897 * on platforms where one or more of the math built-ins are defined as macros
39898 * or inline functions and are thus not suitable to be used as function pointers.
39899 */
39900#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
39901DUK_LOCAL double duk__fabs(double x) {
39902 return DUK_FABS(x);
39903}
39904DUK_LOCAL double duk__acos(double x) {
39905 return DUK_ACOS(x);
39906}
39907DUK_LOCAL double duk__asin(double x) {
39908 return DUK_ASIN(x);
39909}
39910DUK_LOCAL double duk__atan(double x) {
39911 return DUK_ATAN(x);
39912}
39913DUK_LOCAL double duk__ceil(double x) {
39914 return DUK_CEIL(x);
39915}
39916DUK_LOCAL double duk__cos(double x) {
39917 return DUK_COS(x);
39918}
39919DUK_LOCAL double duk__exp(double x) {
39920 return DUK_EXP(x);
39921}
39922DUK_LOCAL double duk__floor(double x) {
39923 return DUK_FLOOR(x);
39924}
39925DUK_LOCAL double duk__log(double x) {
39926 return DUK_LOG(x);
39927}
39928DUK_LOCAL double duk__sin(double x) {
39929 return DUK_SIN(x);
39930}
39931DUK_LOCAL double duk__sqrt(double x) {
39932 return DUK_SQRT(x);
39933}
39934DUK_LOCAL double duk__tan(double x) {
39935 return DUK_TAN(x);
39936}
39937DUK_LOCAL double duk__atan2_fixed(double x, double y) {
39938#if defined(DUK_USE_ATAN2_WORKAROUNDS)
39939 /* Specific fixes to common atan2() implementation issues:
39940 * - test-bug-mingw-math-issues.js
39941 */
39942 if (DUK_ISINF(x) && DUK_ISINF(y)) {
39943 if (DUK_SIGNBIT(x)) {
39944 if (DUK_SIGNBIT(y)) {
39945 return -2.356194490192345;
39946 } else {
39947 return -0.7853981633974483;
39948 }
39949 } else {
39950 if (DUK_SIGNBIT(y)) {
39951 return 2.356194490192345;
39952 } else {
39953 return 0.7853981633974483;
39954 }
39955 }
39956 }
39957#else
39958 /* Some ISO C assumptions. */
39959
39960 DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), 0.7853981633974483));
39961 DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), -0.7853981633974483));
39962 DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), 2.356194490192345));
39963 DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), -2.356194490192345));
39964#endif
39965
39966 return DUK_ATAN2(x, y);
39967}
39968#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
39969
39970/* order must match constants in genbuiltins.py */
39971DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
39972#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
39973 duk__fabs,
39974 duk__acos,
39975 duk__asin,
39976 duk__atan,
39977 duk__ceil,
39978 duk__cos,
39979 duk__exp,
39980 duk__floor,
39981 duk__log,
39982 duk__round_fixed,
39983 duk__sin,
39984 duk__sqrt,
39985 duk__tan,
39986#if defined(DUK_USE_ES6)
39987 duk__cbrt,
39988 duk__log2,
39989 duk__log10,
39990 duk__trunc
39991#endif
39992#else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
39993 DUK_FABS,
39994 DUK_ACOS,
39995 DUK_ASIN,
39996 DUK_ATAN,
39997 DUK_CEIL,
39998 DUK_COS,
39999 DUK_EXP,
40000 DUK_FLOOR,
40001 DUK_LOG,
40002 duk__round_fixed,
40003 DUK_SIN,
40004 DUK_SQRT,
40005 DUK_TAN,
40006#if defined(DUK_USE_ES6)
40007 duk__cbrt,
40008 duk__log2,
40009 duk__log10,
40010 duk__trunc
40011#endif
40012#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
40013};
40014
40015/* order must match constants in genbuiltins.py */
40016DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
40017#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
40018 duk__atan2_fixed,
40019 duk_js_arith_pow
40020#else
40021 duk__atan2_fixed,
40022 duk_js_arith_pow
40023#endif
40024};
40025
40026DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) {
40027 duk_small_int_t fun_idx = duk_get_current_magic(thr);
40028 duk__one_arg_func fun;
40029 duk_double_t arg1;
40030
40031 DUK_ASSERT(fun_idx >= 0);
40032 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
40033 arg1 = duk_to_number(thr, 0);
40034 fun = duk__one_arg_funcs[fun_idx];
40035 duk_push_number(thr, (duk_double_t) fun((double) arg1));
40036 return 1;
40037}
40038
40039DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) {
40040 duk_small_int_t fun_idx = duk_get_current_magic(thr);
40041 duk__two_arg_func fun;
40042 duk_double_t arg1;
40043 duk_double_t arg2;
40044
40045 DUK_ASSERT(fun_idx >= 0);
40046 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
40047 arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */
40048 arg2 = duk_to_number(thr, 1);
40049 fun = duk__two_arg_funcs[fun_idx];
40050 duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2));
40051 return 1;
40052}
40053
40054DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) {
40055 return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
40056}
40057
40058DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) {
40059 return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
40060}
40061
40062DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) {
40063 duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr));
40064 return 1;
40065}
40066
40067#if defined(DUK_USE_ES6)
40068DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) {
40069 /*
40070 * E6 Section 20.2.2.18: Math.hypot
40071 *
40072 * - If no arguments are passed, the result is +0.
40073 * - If any argument is +inf, the result is +inf.
40074 * - If any argument is -inf, the result is +inf.
40075 * - If no argument is +inf or -inf, and any argument is NaN, the result is
40076 * NaN.
40077 * - If all arguments are either +0 or -0, the result is +0.
40078 */
40079
40080 duk_idx_t nargs;
40081 duk_idx_t i;
40082 duk_bool_t found_nan;
40083 duk_double_t max;
40084 duk_double_t sum, summand;
40085 duk_double_t comp, prelim;
40086 duk_double_t t;
40087
40088 nargs = duk_get_top(thr);
40089
40090 /* Find the highest value. Also ToNumber() coerces. */
40091 max = 0.0;
40092 found_nan = 0;
40093 for (i = 0; i < nargs; i++) {
40094 t = DUK_FABS(duk_to_number(thr, i));
40095 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
40096 found_nan = 1;
40097 } else {
40098 max = duk_double_fmax(max, t);
40099 }
40100 }
40101
40102 /* Early return cases. */
40103 if (duk_double_equals(max, DUK_DOUBLE_INFINITY)) {
40104 duk_push_number(thr, DUK_DOUBLE_INFINITY);
40105 return 1;
40106 } else if (found_nan) {
40107 duk_push_number(thr, DUK_DOUBLE_NAN);
40108 return 1;
40109 } else if (duk_double_equals(max, 0.0)) {
40110 duk_push_number(thr, 0.0);
40111 /* Otherwise we'd divide by zero. */
40112 return 1;
40113 }
40114
40115 /* Use Kahan summation and normalize to the highest value to minimize
40116 * floating point rounding error and avoid overflow.
40117 *
40118 * https://en.wikipedia.org/wiki/Kahan_summation_algorithm
40119 */
40120 sum = 0.0;
40121 comp = 0.0;
40122 for (i = 0; i < nargs; i++) {
40123 t = DUK_FABS(duk_get_number(thr, i)) / max;
40124 summand = (t * t) - comp;
40125 prelim = sum + summand;
40126 comp = (prelim - sum) - summand;
40127 sum = prelim;
40128 }
40129
40130 duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max);
40131 return 1;
40132}
40133#endif /* DUK_USE_ES6 */
40134
40135#if defined(DUK_USE_ES6)
40136DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) {
40137 duk_double_t d;
40138
40139 d = duk_to_number(thr, 0);
40140 if (duk_double_is_nan(d)) {
40141 DUK_ASSERT(duk_is_nan(thr, -1));
40142 return 1; /* NaN input -> return NaN */
40143 }
40144 if (duk_double_equals(d, 0.0)) {
40145 /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */
40146 return 1;
40147 }
40148 duk_push_int(thr, (d > 0.0 ? 1 : -1));
40149 return 1;
40150}
40151#endif /* DUK_USE_ES6 */
40152
40153#if defined(DUK_USE_ES6)
40154DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) {
40155 duk_uint32_t x;
40156 duk_small_uint_t i;
40157
40158#if defined(DUK_USE_PREFER_SIZE)
40159 duk_uint32_t mask;
40160
40161 x = duk_to_uint32(thr, 0);
40162 for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) {
40163 if (x & mask) {
40164 break;
40165 }
40166 i++;
40167 }
40168 DUK_ASSERT(i <= 32);
40169 duk_push_uint(thr, i);
40170 return 1;
40171#else /* DUK_USE_PREFER_SIZE */
40172 i = 0;
40173 x = duk_to_uint32(thr, 0);
40174 if (x & 0xffff0000UL) {
40175 x >>= 16;
40176 } else {
40177 i += 16;
40178 }
40179 if (x & 0x0000ff00UL) {
40180 x >>= 8;
40181 } else {
40182 i += 8;
40183 }
40184 if (x & 0x000000f0UL) {
40185 x >>= 4;
40186 } else {
40187 i += 4;
40188 }
40189 if (x & 0x0000000cUL) {
40190 x >>= 2;
40191 } else {
40192 i += 2;
40193 }
40194 if (x & 0x00000002UL) {
40195 x >>= 1;
40196 } else {
40197 i += 1;
40198 }
40199 if (x & 0x00000001UL) {
40200 ;
40201 } else {
40202 i += 1;
40203 }
40204 DUK_ASSERT(i <= 32);
40205 duk_push_uint(thr, i);
40206 return 1;
40207#endif /* DUK_USE_PREFER_SIZE */
40208}
40209#endif /* DUK_USE_ES6 */
40210
40211#if defined(DUK_USE_ES6)
40212DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) {
40213 duk_uint32_t x, y, z;
40214
40215 x = duk_to_uint32(thr, 0);
40216 y = duk_to_uint32(thr, 1);
40217 z = x * y;
40218
40219 /* While arguments are ToUint32() coerced and the multiplication
40220 * is unsigned as such, the final result is curiously interpreted
40221 * as a signed 32-bit value.
40222 */
40223 duk_push_i32(thr, (duk_int32_t) z);
40224 return 1;
40225}
40226#endif /* DUK_USE_ES6 */
40227
40228#endif /* DUK_USE_MATH_BUILTIN */
40229#line 1 "duk_bi_number.c"
40230/*
40231 * Number built-ins
40232 */
40233
40234/* #include duk_internal.h -> already included */
40235
40236#if defined(DUK_USE_NUMBER_BUILTIN)
40237
40238DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
40239 duk_hobject *h;
40240
40241 /* Number built-in accepts a plain number or a Number object (whose
40242 * internal value is operated on). Other types cause TypeError.
40243 */
40244
40245 duk_push_this(thr);
40246 if (duk_is_number(thr, -1)) {
40247 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
40248 goto done;
40249 }
40250 h = duk_get_hobject(thr, -1);
40251 if (!h ||
40252 (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
40253 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
40254 DUK_ERROR_TYPE(thr, "number expected");
40255 DUK_WO_NORETURN(return 0.0;);
40256 }
40257 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
40258 DUK_ASSERT(duk_is_number(thr, -1));
40259 DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
40260 (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
40261 duk_remove_m2(thr);
40262
40263 done:
40264 return duk_get_number(thr, -1);
40265}
40266
40267DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) {
40268 duk_idx_t nargs;
40269 duk_hobject *h_this;
40270
40271 /*
40272 * The Number constructor uses ToNumber(arg) for number coercion
40273 * (coercing an undefined argument to NaN). However, if the
40274 * argument is not given at all, +0 must be used instead. To do
40275 * this, a vararg function is used.
40276 */
40277
40278 nargs = duk_get_top(thr);
40279 if (nargs == 0) {
40280 duk_push_int(thr, 0);
40281 }
40282 duk_to_number(thr, 0);
40283 duk_set_top(thr, 1);
40284 DUK_ASSERT_TOP(thr, 1);
40285
40286 if (!duk_is_constructor_call(thr)) {
40287 return 1;
40288 }
40289
40290 /*
40291 * E5 Section 15.7.2.1 requires that the constructed object
40292 * must have the original Number.prototype as its internal
40293 * prototype. However, since Number.prototype is non-writable
40294 * and non-configurable, this doesn't have to be enforced here:
40295 * The default object (bound to 'this') is OK, though we have
40296 * to change its class.
40297 *
40298 * Internal value set to ToNumber(arg) or +0; if no arg given,
40299 * ToNumber(undefined) = NaN, so special treatment is needed
40300 * (above). String internal value is immutable.
40301 */
40302
40303 /* XXX: helper */
40304 duk_push_this(thr);
40305 h_this = duk_known_hobject(thr, -1);
40306 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
40307
40308 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
40309 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
40310 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
40311
40312 duk_dup_0(thr); /* -> [ val obj val ] */
40313 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
40314 return 0; /* no return value -> don't replace created value */
40315}
40316
40317DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) {
40318 (void) duk__push_this_number_plain(thr);
40319 return 1;
40320}
40321
40322DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) {
40323 duk_small_int_t radix;
40324 duk_small_uint_t n2s_flags;
40325
40326 (void) duk__push_this_number_plain(thr);
40327 if (duk_is_undefined(thr, 0)) {
40328 radix = 10;
40329 } else {
40330 radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36);
40331 }
40332 DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
40333
40334 n2s_flags = 0;
40335
40336 duk_numconv_stringify(thr,
40337 radix /*radix*/,
40338 0 /*digits*/,
40339 n2s_flags /*flags*/);
40340 return 1;
40341}
40342
40343DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) {
40344 /* XXX: just use toString() for now; permitted although not recommended.
40345 * nargs==1, so radix is passed to toString().
40346 */
40347 return duk_bi_number_prototype_to_string(thr);
40348}
40349
40350/*
40351 * toFixed(), toExponential(), toPrecision()
40352 */
40353
40354/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
40355
40356DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
40357 duk_small_int_t frac_digits;
40358 duk_double_t d;
40359 duk_small_int_t c;
40360 duk_small_uint_t n2s_flags;
40361
40362 /* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number
40363 * value' check is done first.
40364 */
40365 d = duk__push_this_number_plain(thr);
40366 frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
40367
40368 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
40369 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
40370 goto use_to_string;
40371 }
40372
40373 if (d >= 1.0e21 || d <= -1.0e21) {
40374 goto use_to_string;
40375 }
40376
40377 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
40378 DUK_N2S_FLAG_FRACTION_DIGITS;
40379
40380 duk_numconv_stringify(thr,
40381 10 /*radix*/,
40382 frac_digits /*digits*/,
40383 n2s_flags /*flags*/);
40384 return 1;
40385
40386 use_to_string:
40387 DUK_ASSERT_TOP(thr, 2);
40388 duk_to_string(thr, -1);
40389 return 1;
40390}
40391
40392DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) {
40393 duk_bool_t frac_undefined;
40394 duk_small_int_t frac_digits;
40395 duk_double_t d;
40396 duk_small_int_t c;
40397 duk_small_uint_t n2s_flags;
40398
40399 d = duk__push_this_number_plain(thr);
40400
40401 frac_undefined = duk_is_undefined(thr, 0);
40402 duk_to_int(thr, 0); /* for side effects */
40403
40404 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
40405 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
40406 goto use_to_string;
40407 }
40408
40409 frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
40410
40411 n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
40412 (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
40413
40414 duk_numconv_stringify(thr,
40415 10 /*radix*/,
40416 frac_digits + 1 /*leading digit + fractions*/,
40417 n2s_flags /*flags*/);
40418 return 1;
40419
40420 use_to_string:
40421 DUK_ASSERT_TOP(thr, 2);
40422 duk_to_string(thr, -1);
40423 return 1;
40424}
40425
40426DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
40427 /* The specification has quite awkward order of coercion and
40428 * checks for toPrecision(). The operations below are a bit
40429 * reordered, within constraints of observable side effects.
40430 */
40431
40432 duk_double_t d;
40433 duk_small_int_t prec;
40434 duk_small_int_t c;
40435 duk_small_uint_t n2s_flags;
40436
40437 DUK_ASSERT_TOP(thr, 1);
40438
40439 d = duk__push_this_number_plain(thr);
40440 if (duk_is_undefined(thr, 0)) {
40441 goto use_to_string;
40442 }
40443 DUK_ASSERT_TOP(thr, 2);
40444
40445 duk_to_int(thr, 0); /* for side effects */
40446
40447 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
40448 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
40449 goto use_to_string;
40450 }
40451
40452 prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21);
40453
40454 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
40455 DUK_N2S_FLAG_NO_ZERO_PAD;
40456
40457 duk_numconv_stringify(thr,
40458 10 /*radix*/,
40459 prec /*digits*/,
40460 n2s_flags /*flags*/);
40461 return 1;
40462
40463 use_to_string:
40464 /* Used when precision is undefined; also used for NaN (-> "NaN"),
40465 * and +/- infinity (-> "Infinity", "-Infinity").
40466 */
40467
40468 DUK_ASSERT_TOP(thr, 2);
40469 duk_to_string(thr, -1);
40470 return 1;
40471}
40472
40473/*
40474 * ES2015 isFinite() etc
40475 */
40476
40477#if defined(DUK_USE_ES6)
40478DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) {
40479 duk_int_t magic;
40480 duk_bool_t ret = 0;
40481
40482 if (duk_is_number(thr, 0)) {
40483 duk_double_t d;
40484
40485 magic = duk_get_current_magic(thr);
40486 d = duk_get_number(thr, 0);
40487
40488 switch (magic) {
40489 case 0: /* isFinite() */
40490 ret = duk_double_is_finite(d);
40491 break;
40492 case 1: /* isInteger() */
40493 ret = duk_double_is_integer(d);
40494 break;
40495 case 2: /* isNaN() */
40496 ret = duk_double_is_nan(d);
40497 break;
40498 default: /* isSafeInteger() */
40499 DUK_ASSERT(magic == 3);
40500 ret = duk_double_is_safe_integer(d);
40501 }
40502 }
40503
40504 duk_push_boolean(thr, ret);
40505 return 1;
40506}
40507#endif /* DUK_USE_ES6 */
40508
40509#endif /* DUK_USE_NUMBER_BUILTIN */
40510#line 1 "duk_bi_object.c"
40511/*
40512 * Object built-ins
40513 */
40514
40515/* #include duk_internal.h -> already included */
40516
40517/* Needed even when Object built-in disabled. */
40518DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
40519 duk_tval *tv;
40520
40521 tv = DUK_HTHREAD_THIS_PTR(thr);
40522 duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/);
40523 return 1;
40524}
40525
40526#if defined(DUK_USE_OBJECT_BUILTIN)
40527DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) {
40528 duk_uint_t arg_mask;
40529
40530 arg_mask = duk_get_type_mask(thr, 0);
40531
40532 if (!duk_is_constructor_call(thr) && /* not a constructor call */
40533 ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */
40534 duk_to_object(thr, 0);
40535 return 1;
40536 }
40537
40538 /* Pointer and buffer primitive values are treated like other
40539 * primitives values which have a fully fledged object counterpart:
40540 * promote to an object value. Lightfuncs and plain buffers are
40541 * coerced with ToObject() even they could also be returned as is.
40542 */
40543 if (arg_mask & (DUK_TYPE_MASK_OBJECT |
40544 DUK_TYPE_MASK_STRING |
40545 DUK_TYPE_MASK_BOOLEAN |
40546 DUK_TYPE_MASK_NUMBER |
40547 DUK_TYPE_MASK_POINTER |
40548 DUK_TYPE_MASK_BUFFER |
40549 DUK_TYPE_MASK_LIGHTFUNC)) {
40550 /* For DUK_TYPE_OBJECT the coercion is a no-op and could
40551 * be checked for explicitly, but Object(obj) calls are
40552 * not very common so opt for minimal footprint.
40553 */
40554 duk_to_object(thr, 0);
40555 return 1;
40556 }
40557
40558 (void) duk_push_object_helper(thr,
40559 DUK_HOBJECT_FLAG_EXTENSIBLE |
40560 DUK_HOBJECT_FLAG_FASTREFS |
40561 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
40562 DUK_BIDX_OBJECT_PROTOTYPE);
40563 return 1;
40564}
40565#endif /* DUK_USE_OBJECT_BUILTIN */
40566
40567#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
40568DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) {
40569 duk_idx_t nargs;
40570 duk_int_t idx;
40571
40572 nargs = duk_get_top_require_min(thr, 1 /*min_top*/);
40573
40574 duk_to_object(thr, 0);
40575 for (idx = 1; idx < nargs; idx++) {
40576 /* E7 19.1.2.1 (step 4a) */
40577 if (duk_is_null_or_undefined(thr, idx)) {
40578 continue;
40579 }
40580
40581 /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
40582 * convenient here.
40583 */
40584 duk_to_object(thr, idx);
40585 duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
40586 while (duk_next(thr, -1, 1 /*get_value*/)) {
40587 /* [ target ... enum key value ] */
40588 duk_put_prop(thr, 0);
40589 /* [ target ... enum ] */
40590 }
40591 /* Could pop enumerator, but unnecessary because of duk_set_top()
40592 * below.
40593 */
40594 }
40595
40596 duk_set_top(thr, 1);
40597 return 1;
40598}
40599#endif
40600
40601#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
40602DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) {
40603 DUK_ASSERT_TOP(thr, 2);
40604 duk_push_boolean(thr, duk_samevalue(thr, 0, 1));
40605 return 1;
40606}
40607#endif
40608
40609#if defined(DUK_USE_OBJECT_BUILTIN)
40610DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) {
40611 duk_hobject *proto;
40612
40613 DUK_ASSERT_TOP(thr, 2);
40614
40615#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
40616 duk_hbufobj_promote_plain(thr, 0);
40617#endif
40618 proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL);
40619 DUK_ASSERT(proto != NULL || duk_is_null(thr, 0));
40620
40621 (void) duk_push_object_helper_proto(thr,
40622 DUK_HOBJECT_FLAG_EXTENSIBLE |
40623 DUK_HOBJECT_FLAG_FASTREFS |
40624 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
40625 proto);
40626
40627 if (!duk_is_undefined(thr, 1)) {
40628 /* [ O Properties obj ] */
40629
40630 duk_replace(thr, 0);
40631
40632 /* [ obj Properties ] */
40633
40634 /* Just call the "original" Object.defineProperties() to
40635 * finish up.
40636 */
40637
40638 return duk_bi_object_constructor_define_properties(thr);
40639 }
40640
40641 /* [ O Properties obj ] */
40642
40643 return 1;
40644}
40645#endif /* DUK_USE_OBJECT_BUILTIN */
40646
40647#if defined(DUK_USE_OBJECT_BUILTIN)
40648DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) {
40649 duk_small_uint_t pass;
40650 duk_uint_t defprop_flags;
40651 duk_hobject *obj;
40652 duk_idx_t idx_value;
40653 duk_hobject *get;
40654 duk_hobject *set;
40655
40656 /* Lightfunc and plain buffer handling by ToObject() coercion. */
40657 obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
40658 DUK_ASSERT(obj != NULL);
40659
40660 duk_to_object(thr, 1); /* properties object */
40661
40662 DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
40663 (duk_tval *) duk_get_tval(thr, 0),
40664 (duk_tval *) duk_get_tval(thr, 1)));
40665
40666 /*
40667 * Two pass approach to processing the property descriptors.
40668 * On first pass validate and normalize all descriptors before
40669 * any changes are made to the target object. On second pass
40670 * make the actual modifications to the target object.
40671 *
40672 * Right now we'll just use the same normalize/validate helper
40673 * on both passes, ignoring its outputs on the first pass.
40674 */
40675
40676 for (pass = 0; pass < 2; pass++) {
40677 duk_set_top(thr, 2); /* -> [ hobject props ] */
40678 duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
40679
40680 for (;;) {
40681 duk_hstring *key;
40682
40683 /* [ hobject props enum(props) ] */
40684
40685 duk_set_top(thr, 3);
40686
40687 if (!duk_next(thr, 2, 1 /*get_value*/)) {
40688 break;
40689 }
40690
40691 DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
40692 (duk_tval *) duk_get_tval(thr, -2),
40693 (duk_tval *) duk_get_tval(thr, -1)));
40694
40695 /* [ hobject props enum(props) key desc ] */
40696
40697 duk_hobject_prepare_property_descriptor(thr,
40698 4 /*idx_desc*/,
40699 &defprop_flags,
40700 &idx_value,
40701 &get,
40702 &set);
40703
40704 /* [ hobject props enum(props) key desc [multiple values] ] */
40705
40706 if (pass == 0) {
40707 continue;
40708 }
40709
40710 /* This allows symbols on purpose. */
40711 key = duk_known_hstring(thr, 3);
40712 DUK_ASSERT(key != NULL);
40713
40714 duk_hobject_define_property_helper(thr,
40715 defprop_flags,
40716 obj,
40717 key,
40718 idx_value,
40719 get,
40720 set,
40721 1 /*throw_flag*/);
40722 }
40723 }
40724
40725 /*
40726 * Return target object
40727 */
40728
40729 duk_dup_0(thr);
40730 return 1;
40731}
40732#endif /* DUK_USE_OBJECT_BUILTIN */
40733
40734#if defined(DUK_USE_OBJECT_BUILTIN)
40735DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) {
40736 DUK_ASSERT_TOP(thr, 1);
40737
40738 duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/);
40739 return 1;
40740}
40741#endif /* DUK_USE_OBJECT_BUILTIN */
40742
40743#if defined(DUK_USE_OBJECT_BUILTIN)
40744DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) {
40745 duk_hobject *h;
40746 duk_bool_t is_frozen;
40747 duk_uint_t mask;
40748
40749 is_frozen = (duk_bool_t) duk_get_current_magic(thr);
40750 mask = duk_get_type_mask(thr, 0);
40751 if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
40752 DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
40753 duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
40754 1 : /* lightfunc always frozen and sealed */
40755 (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
40756 } else {
40757 /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
40758 * is considered to be already sealed and frozen.
40759 */
40760 h = duk_get_hobject(thr, 0);
40761 duk_push_boolean(thr, (h == NULL) ||
40762 duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/));
40763 }
40764 return 1;
40765}
40766#endif /* DUK_USE_OBJECT_BUILTIN */
40767
40768#if defined(DUK_USE_OBJECT_BUILTIN)
40769DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) {
40770 DUK_ASSERT_TOP(thr, 0);
40771 (void) duk_push_this_coercible_to_object(thr);
40772 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING);
40773#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
40774 duk_require_callable(thr, 1);
40775#endif
40776 duk_dup_0(thr); /* -> [ O toString O ] */
40777 duk_call_method(thr, 0); /* XXX: call method tail call? */
40778 return 1;
40779}
40780#endif /* DUK_USE_OBJECT_BUILTIN */
40781
40782#if defined(DUK_USE_OBJECT_BUILTIN)
40783DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) {
40784 /* For lightfuncs and plain buffers, returns Object() coerced. */
40785 (void) duk_push_this_coercible_to_object(thr);
40786 return 1;
40787}
40788#endif /* DUK_USE_OBJECT_BUILTIN */
40789
40790#if defined(DUK_USE_OBJECT_BUILTIN)
40791DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) {
40792 duk_hobject *h_v;
40793 duk_hobject *h_obj;
40794
40795 DUK_ASSERT_TOP(thr, 1);
40796
40797 h_v = duk_get_hobject(thr, 0);
40798 if (!h_v) {
40799 duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */
40800 return 1;
40801 }
40802
40803 h_obj = duk_push_this_coercible_to_object(thr);
40804 DUK_ASSERT(h_obj != NULL);
40805
40806 /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
40807 * Prototype loops should cause an error to be thrown.
40808 */
40809 duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
40810 return 1;
40811}
40812#endif /* DUK_USE_OBJECT_BUILTIN */
40813
40814#if defined(DUK_USE_OBJECT_BUILTIN)
40815DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) {
40816 return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/);
40817}
40818#endif /* DUK_USE_OBJECT_BUILTIN */
40819
40820#if defined(DUK_USE_OBJECT_BUILTIN)
40821DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) {
40822 return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
40823}
40824#endif /* DUK_USE_OBJECT_BUILTIN */
40825
40826#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
40827/* Shared helper to implement Object.getPrototypeOf,
40828 * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf.
40829 *
40830 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
40831 */
40832DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) {
40833 /*
40834 * magic = 0: __proto__ getter
40835 * magic = 1: Object.getPrototypeOf()
40836 * magic = 2: Reflect.getPrototypeOf()
40837 */
40838
40839 duk_hobject *h;
40840 duk_hobject *proto;
40841 duk_tval *tv;
40842 duk_int_t magic;
40843
40844 magic = duk_get_current_magic(thr);
40845
40846 if (magic == 0) {
40847 DUK_ASSERT_TOP(thr, 0);
40848 duk_push_this_coercible_to_object(thr);
40849 }
40850 DUK_ASSERT(duk_get_top(thr) >= 1);
40851 if (magic < 2) {
40852 /* ES2015 Section 19.1.2.9, step 1 */
40853 duk_to_object(thr, 0);
40854 }
40855 tv = DUK_GET_TVAL_POSIDX(thr, 0);
40856
40857 switch (DUK_TVAL_GET_TAG(tv)) {
40858 case DUK_TAG_BUFFER:
40859 proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
40860 break;
40861 case DUK_TAG_LIGHTFUNC:
40862 proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
40863 break;
40864 case DUK_TAG_OBJECT:
40865 h = DUK_TVAL_GET_OBJECT(tv);
40866 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
40867 break;
40868 default:
40869 /* This implicitly handles CheckObjectCoercible() caused
40870 * TypeError.
40871 */
40872 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
40873 }
40874 if (proto != NULL) {
40875 duk_push_hobject(thr, proto);
40876 } else {
40877 duk_push_null(thr);
40878 }
40879 return 1;
40880}
40881#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
40882
40883#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
40884/* Shared helper to implement ES2015 Object.setPrototypeOf,
40885 * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
40886 *
40887 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
40888 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
40889 */
40890DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
40891 /*
40892 * magic = 0: __proto__ setter
40893 * magic = 1: Object.setPrototypeOf()
40894 * magic = 2: Reflect.setPrototypeOf()
40895 */
40896
40897 duk_hobject *h_obj;
40898 duk_hobject *h_new_proto;
40899 duk_hobject *h_curr;
40900 duk_ret_t ret_success = 1; /* retval for success path */
40901 duk_uint_t mask;
40902 duk_int_t magic;
40903
40904 /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
40905 magic = duk_get_current_magic(thr);
40906 if (magic == 0) {
40907 duk_push_this_check_object_coercible(thr);
40908 duk_insert(thr, 0);
40909 if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
40910 return 0;
40911 }
40912
40913 /* __proto__ setter returns 'undefined' on success unlike the
40914 * setPrototypeOf() call which returns the target object.
40915 */
40916 ret_success = 0;
40917 } else {
40918 if (magic == 1) {
40919 duk_require_object_coercible(thr, 0);
40920 } else {
40921 duk_require_hobject_accept_mask(thr, 0,
40922 DUK_TYPE_MASK_LIGHTFUNC |
40923 DUK_TYPE_MASK_BUFFER);
40924 }
40925 duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
40926 }
40927
40928 h_new_proto = duk_get_hobject(thr, 1);
40929 /* h_new_proto may be NULL */
40930
40931 mask = duk_get_type_mask(thr, 0);
40932 if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
40933 duk_hobject *curr_proto;
40934 curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
40935 DUK_BIDX_FUNCTION_PROTOTYPE :
40936 DUK_BIDX_UINT8ARRAY_PROTOTYPE];
40937 if (h_new_proto == curr_proto) {
40938 goto skip;
40939 }
40940 goto fail_nonextensible;
40941 }
40942 h_obj = duk_get_hobject(thr, 0);
40943 if (h_obj == NULL) {
40944 goto skip;
40945 }
40946 DUK_ASSERT(h_obj != NULL);
40947
40948 /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
40949 /* TODO: implement Proxy object support here */
40950
40951 if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
40952 goto skip;
40953 }
40954 if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
40955 goto fail_nonextensible;
40956 }
40957 for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
40958 /* Loop prevention. */
40959 if (h_curr == h_obj) {
40960 goto fail_loop;
40961 }
40962 }
40963 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
40964 /* fall thru */
40965
40966 skip:
40967 duk_set_top(thr, 1);
40968 if (magic == 2) {
40969 duk_push_true(thr);
40970 }
40971 return ret_success;
40972
40973 fail_nonextensible:
40974 fail_loop:
40975 if (magic != 2) {
40976 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
40977 } else {
40978 duk_push_false(thr);
40979 return 1;
40980 }
40981}
40982#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
40983
40984#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
40985DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) {
40986 /*
40987 * magic = 0: Object.defineProperty()
40988 * magic = 1: Reflect.defineProperty()
40989 */
40990
40991 duk_hobject *obj;
40992 duk_hstring *key;
40993 duk_hobject *get;
40994 duk_hobject *set;
40995 duk_idx_t idx_value;
40996 duk_uint_t defprop_flags;
40997 duk_small_uint_t magic;
40998 duk_bool_t throw_flag;
40999 duk_bool_t ret;
41000
41001 DUK_ASSERT(thr != NULL);
41002
41003 DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
41004 (void *) thr,
41005 (duk_tval *) duk_get_tval(thr, 0),
41006 (duk_tval *) duk_get_tval(thr, 1),
41007 (duk_tval *) duk_get_tval(thr, 2)));
41008
41009 /* [ obj key desc ] */
41010
41011 magic = (duk_small_uint_t) duk_get_current_magic(thr);
41012
41013 /* Lightfuncs are currently supported by coercing to a temporary
41014 * Function object; changes will be allowed (the coerced value is
41015 * extensible) but will be lost. Same for plain buffers.
41016 */
41017 obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
41018 DUK_ASSERT(obj != NULL);
41019 key = duk_to_property_key_hstring(thr, 1);
41020 (void) duk_require_hobject(thr, 2);
41021
41022 DUK_ASSERT(obj != NULL);
41023 DUK_ASSERT(key != NULL);
41024 DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
41025
41026 /*
41027 * Validate and convert argument property descriptor (an ECMAScript
41028 * object) into a set of defprop_flags and possibly property value,
41029 * getter, and/or setter values on the value stack.
41030 *
41031 * Lightfunc set/get values are coerced to full Functions.
41032 */
41033
41034 duk_hobject_prepare_property_descriptor(thr,
41035 2 /*idx_desc*/,
41036 &defprop_flags,
41037 &idx_value,
41038 &get,
41039 &set);
41040
41041 /*
41042 * Use Object.defineProperty() helper for the actual operation.
41043 */
41044
41045 DUK_ASSERT(magic == 0U || magic == 1U);
41046 throw_flag = magic ^ 1U;
41047 ret = duk_hobject_define_property_helper(thr,
41048 defprop_flags,
41049 obj,
41050 key,
41051 idx_value,
41052 get,
41053 set,
41054 throw_flag);
41055
41056 /* Ignore the normalize/validate helper outputs on the value stack,
41057 * they're popped automatically.
41058 */
41059
41060 if (magic == 0U) {
41061 /* Object.defineProperty(): return target object. */
41062 duk_push_hobject(thr, obj);
41063 } else {
41064 /* Reflect.defineProperty(): return success/fail. */
41065 duk_push_boolean(thr, ret);
41066 }
41067 return 1;
41068}
41069#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
41070
41071#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
41072DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) {
41073 DUK_ASSERT_TOP(thr, 2);
41074
41075 /* ES2015 Section 19.1.2.6, step 1 */
41076 if (duk_get_current_magic(thr) == 0) {
41077 duk_to_object(thr, 0);
41078 }
41079
41080 /* [ obj key ] */
41081
41082 duk_hobject_object_get_own_property_descriptor(thr, -2);
41083 return 1;
41084}
41085#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
41086
41087#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
41088DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) {
41089 /*
41090 * magic = 0: Object.isExtensible()
41091 * magic = 1: Reflect.isExtensible()
41092 */
41093
41094 duk_hobject *h;
41095
41096 if (duk_get_current_magic(thr) == 0) {
41097 h = duk_get_hobject(thr, 0);
41098 } else {
41099 /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
41100 * and plain buffers here because they pretend to be objects.
41101 */
41102 h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
41103 }
41104
41105 duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
41106 return 1;
41107}
41108#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
41109
41110#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
41111/* Shared helper for various key/symbol listings, magic:
41112 * 0=Object.keys()
41113 * 1=Object.getOwnPropertyNames(),
41114 * 2=Object.getOwnPropertySymbols(),
41115 * 3=Reflect.ownKeys()
41116 */
41117DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
41118 /* Object.keys() */
41119 DUK_ENUM_OWN_PROPERTIES_ONLY |
41120 DUK_ENUM_NO_PROXY_BEHAVIOR,
41121
41122 /* Object.getOwnPropertyNames() */
41123 DUK_ENUM_INCLUDE_NONENUMERABLE |
41124 DUK_ENUM_OWN_PROPERTIES_ONLY |
41125 DUK_ENUM_NO_PROXY_BEHAVIOR,
41126
41127 /* Object.getOwnPropertySymbols() */
41128 DUK_ENUM_INCLUDE_SYMBOLS |
41129 DUK_ENUM_OWN_PROPERTIES_ONLY |
41130 DUK_ENUM_EXCLUDE_STRINGS |
41131 DUK_ENUM_INCLUDE_NONENUMERABLE |
41132 DUK_ENUM_NO_PROXY_BEHAVIOR,
41133
41134 /* Reflect.ownKeys() */
41135 DUK_ENUM_INCLUDE_SYMBOLS |
41136 DUK_ENUM_OWN_PROPERTIES_ONLY |
41137 DUK_ENUM_INCLUDE_NONENUMERABLE |
41138 DUK_ENUM_NO_PROXY_BEHAVIOR
41139};
41140
41141DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
41142 duk_hobject *obj;
41143#if defined(DUK_USE_ES6_PROXY)
41144 duk_hobject *h_proxy_target;
41145 duk_hobject *h_proxy_handler;
41146 duk_hobject *h_trap_result;
41147#endif
41148 duk_small_uint_t enum_flags;
41149 duk_int_t magic;
41150
41151 DUK_ASSERT_TOP(thr, 1);
41152
41153 magic = duk_get_current_magic(thr);
41154 if (magic == 3) {
41155 /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs
41156 * and plain buffers pretend to be objects, so accept those too.
41157 */
41158 obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
41159 } else {
41160 /* ES2015: ToObject coerce. */
41161 obj = duk_to_hobject(thr, 0);
41162 }
41163 DUK_ASSERT(obj != NULL);
41164 DUK_UNREF(obj);
41165
41166 /* XXX: proxy chains */
41167
41168#if defined(DUK_USE_ES6_PROXY)
41169 /* XXX: better sharing of code between proxy target call sites */
41170 if (DUK_LIKELY(!duk_hobject_proxy_check(obj,
41171 &h_proxy_target,
41172 &h_proxy_handler))) {
41173 goto skip_proxy;
41174 }
41175
41176 duk_push_hobject(thr, h_proxy_handler);
41177 if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
41178 /* Careful with reachability here: don't pop 'obj' before pushing
41179 * proxy target.
41180 */
41181 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
41182 duk_pop_2(thr);
41183 duk_push_hobject(thr, h_proxy_target);
41184 duk_replace(thr, 0);
41185 DUK_ASSERT_TOP(thr, 1);
41186 goto skip_proxy;
41187 }
41188
41189 /* [ obj handler trap ] */
41190 duk_insert(thr, -2);
41191 duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */
41192 duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */
41193 h_trap_result = duk_require_hobject(thr, -1);
41194 DUK_UNREF(h_trap_result);
41195
41196 magic = duk_get_current_magic(thr);
41197 DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
41198 enum_flags = duk__object_keys_enum_flags[magic];
41199
41200 duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
41201 return 1;
41202
41203 skip_proxy:
41204#endif /* DUK_USE_ES6_PROXY */
41205
41206 DUK_ASSERT_TOP(thr, 1);
41207 magic = duk_get_current_magic(thr);
41208 DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
41209 enum_flags = duk__object_keys_enum_flags[magic];
41210 return duk_hobject_get_enumerated_keys(thr, enum_flags);
41211}
41212#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
41213
41214#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
41215DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) {
41216 /*
41217 * magic = 0: Object.preventExtensions()
41218 * magic = 1: Reflect.preventExtensions()
41219 */
41220
41221 duk_hobject *h;
41222 duk_uint_t mask;
41223 duk_int_t magic;
41224
41225 magic = duk_get_current_magic(thr);
41226
41227 /* Silent success for lightfuncs and plain buffers always. */
41228 mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
41229
41230 /* Object.preventExtensions() silent success for non-object. */
41231 if (magic == 0) {
41232 mask |= DUK_TYPE_MASK_UNDEFINED |
41233 DUK_TYPE_MASK_NULL |
41234 DUK_TYPE_MASK_BOOLEAN |
41235 DUK_TYPE_MASK_NUMBER |
41236 DUK_TYPE_MASK_STRING |
41237 DUK_TYPE_MASK_POINTER;
41238 }
41239
41240 if (duk_check_type_mask(thr, 0, mask)) {
41241 /* Not an object, already non-extensible so always success. */
41242 goto done;
41243 }
41244 h = duk_require_hobject(thr, 0);
41245 DUK_ASSERT(h != NULL);
41246
41247 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
41248
41249 /* A non-extensible object cannot gain any more properties,
41250 * so this is a good time to compact.
41251 */
41252 duk_hobject_compact_props(thr, h);
41253
41254 done:
41255 if (magic == 1) {
41256 duk_push_true(thr);
41257 }
41258 return 1;
41259}
41260#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
41261
41262/*
41263 * __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
41264 */
41265
41266#if defined(DUK_USE_ES8)
41267DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) {
41268 duk_push_this(thr);
41269 duk_insert(thr, 0);
41270 duk_to_object(thr, 0);
41271 duk_require_callable(thr, 2);
41272
41273 /* [ ToObject(this) key getter/setter ] */
41274
41275 /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */
41276 duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE |
41277 DUK_DEFPROP_SET_CONFIGURABLE |
41278 (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER));
41279 return 0;
41280}
41281DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) {
41282 duk_uint_t sanity;
41283
41284 duk_push_this(thr);
41285 duk_to_object(thr, -1);
41286
41287 /* XXX: Prototype walk (with sanity) should be a core property
41288 * operation, could add a flag to e.g. duk_get_prop_desc().
41289 */
41290
41291 /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */
41292 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
41293 while (!duk_is_undefined(thr, -1)) {
41294 /* [ key obj ] */
41295 duk_dup(thr, 0);
41296 duk_get_prop_desc(thr, 1, 0 /*flags*/);
41297 if (!duk_is_undefined(thr, -1)) {
41298 duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET));
41299 return 1;
41300 }
41301 duk_pop(thr);
41302
41303 if (DUK_UNLIKELY(sanity-- == 0)) {
41304 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
41305 DUK_WO_NORETURN(return 0;);
41306 }
41307
41308 duk_get_prototype(thr, -1);
41309 duk_remove(thr, -2);
41310 }
41311 return 1;
41312}
41313#endif /* DUK_USE_ES8 */
41314#line 1 "duk_bi_performance.c"
41315/*
41316 * High resolution time API (performance.now() et al)
41317 *
41318 * API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/
41319 */
41320
41321/* #include duk_internal.h -> already included */
41322
41323#if defined(DUK_USE_PERFORMANCE_BUILTIN)
41324DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) {
41325 /* From API spec:
41326 * The DOMHighResTimeStamp type is used to store a time value in
41327 * milliseconds, measured relative from the time origin, global
41328 * monotonic clock, or a time value that represents a duration
41329 * between two DOMHighResTimeStamp's.
41330 */
41331 duk_push_number(thr, duk_time_get_monotonic_time(thr));
41332 return 1;
41333}
41334
41335#if 0 /* Missing until semantics decided. */
41336DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) {
41337 /* No decision yet how to handle timeOrigins, e.g. should one be
41338 * initialized per heap, or per global object set. See
41339 * https://www.w3.org/TR/hr-time/#time-origin.
41340 */
41341 duk_push_uint(thr, 0);
41342 return 1;
41343}
41344#endif /* 0 */
41345#endif /* DUK_USE_PERFORMANCE_BUILTIN */
41346#line 1 "duk_bi_pointer.c"
41347/*
41348 * Pointer built-ins
41349 */
41350
41351/* #include duk_internal.h -> already included */
41352
41353/*
41354 * Constructor
41355 */
41356
41357DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) {
41358 /* XXX: this behavior is quite useless now; it would be nice to be able
41359 * to create pointer values from e.g. numbers or strings. Numbers are
41360 * problematic on 64-bit platforms though. Hex encoded strings?
41361 */
41362 if (duk_get_top(thr) == 0) {
41363 duk_push_pointer(thr, NULL);
41364 } else {
41365 duk_to_pointer(thr, 0);
41366 }
41367 DUK_ASSERT(duk_is_pointer(thr, 0));
41368 duk_set_top(thr, 1);
41369
41370 if (duk_is_constructor_call(thr)) {
41371 (void) duk_push_object_helper(thr,
41372 DUK_HOBJECT_FLAG_EXTENSIBLE |
41373 DUK_HOBJECT_FLAG_FASTREFS |
41374 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
41375 DUK_BIDX_POINTER_PROTOTYPE);
41376
41377 /* Pointer object internal value is immutable. */
41378 duk_dup_0(thr);
41379 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
41380 }
41381 /* Note: unbalanced stack on purpose */
41382
41383 return 1;
41384}
41385
41386/*
41387 * toString(), valueOf()
41388 */
41389
41390DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) {
41391 duk_tval *tv;
41392 duk_small_int_t to_string = duk_get_current_magic(thr);
41393
41394 duk_push_this(thr);
41395 tv = duk_require_tval(thr, -1);
41396 DUK_ASSERT(tv != NULL);
41397
41398 if (DUK_TVAL_IS_POINTER(tv)) {
41399 /* nop */
41400 } else if (DUK_TVAL_IS_OBJECT(tv)) {
41401 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
41402 DUK_ASSERT(h != NULL);
41403
41404 /* Must be a "pointer object", i.e. class "Pointer" */
41405 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
41406 goto type_error;
41407 }
41408
41409 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
41410 } else {
41411 goto type_error;
41412 }
41413
41414 if (to_string) {
41415 duk_to_string(thr, -1);
41416 }
41417 return 1;
41418
41419 type_error:
41420 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
41421}
41422#line 1 "duk_bi_promise.c"
41423/*
41424 * Promise built-in
41425 */
41426
41427/* #include duk_internal.h -> already included */
41428
41429#if defined(DUK_USE_PROMISE_BUILTIN)
41430
41431DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
41432 DUK_ERROR_TYPE(thr, "unimplemented");
41433 DUK_WO_NORETURN(return 0;);
41434}
41435
41436DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
41437 DUK_ERROR_TYPE(thr, "unimplemented");
41438 DUK_WO_NORETURN(return 0;);
41439}
41440
41441DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
41442 DUK_ERROR_TYPE(thr, "unimplemented");
41443 DUK_WO_NORETURN(return 0;);
41444}
41445
41446DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
41447 DUK_ERROR_TYPE(thr, "unimplemented");
41448 DUK_WO_NORETURN(return 0;);
41449}
41450
41451DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
41452 DUK_ERROR_TYPE(thr, "unimplemented");
41453 DUK_WO_NORETURN(return 0;);
41454}
41455
41456DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
41457 DUK_ERROR_TYPE(thr, "unimplemented");
41458 DUK_WO_NORETURN(return 0;);
41459}
41460
41461DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
41462 DUK_ERROR_TYPE(thr, "unimplemented");
41463 DUK_WO_NORETURN(return 0;);
41464}
41465
41466#endif /* DUK_USE_PROMISE_BUILTIN */
41467#line 1 "duk_bi_proxy.c"
41468/*
41469 * Proxy built-in (ES2015)
41470 */
41471
41472/* #include duk_internal.h -> already included */
41473
41474#if defined(DUK_USE_ES6_PROXY)
41475/* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up
41476 * array of valid result keys (strings or symbols). TypeError for invalid
41477 * values. Flags are shared with duk_enum().
41478 */
41479DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
41480 duk_uarridx_t i, len, idx;
41481 duk_propdesc desc;
41482
41483 DUK_CTX_ASSERT_VALID(thr);
41484 DUK_ASSERT(h_proxy_target != NULL);
41485
41486 len = (duk_uarridx_t) duk_get_length(thr, -1);
41487 idx = 0;
41488 duk_push_array(thr);
41489 /* XXX: preallocated dense array, fill in directly */
41490 for (i = 0; i < len; i++) {
41491 duk_hstring *h;
41492
41493 /* [ obj trap_result res_arr ] */
41494 (void) duk_get_prop_index(thr, -2, i);
41495 h = duk_get_hstring(thr, -1);
41496 if (h == NULL) {
41497 DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
41498 DUK_WO_NORETURN(return;);
41499 }
41500
41501 if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
41502 /* No support for 'getOwnPropertyDescriptor' trap yet,
41503 * so check enumerability always from target object
41504 * descriptor.
41505 */
41506 if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
41507 if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
41508 DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
41509 goto skip_key;
41510 }
41511 } else {
41512 DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
41513 goto skip_key;
41514 }
41515 }
41516 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
41517 if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
41518 DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
41519 goto skip_key;
41520 }
41521 if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
41522 DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
41523 goto skip_key;
41524 }
41525 } else {
41526 if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
41527 DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
41528 goto skip_key;
41529 }
41530 }
41531
41532 /* [ obj trap_result res_arr propname ] */
41533 duk_push_uarridx(thr, idx++);
41534 duk_insert(thr, -2);
41535 duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC);
41536 continue;
41537
41538 skip_key:
41539 duk_pop(thr);
41540 continue;
41541 }
41542
41543 /* XXX: Missing trap result validation for non-configurable target keys
41544 * (must be present), for non-extensible target all target keys must be
41545 * present and no extra keys can be present.
41546 * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
41547 */
41548
41549 /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor"
41550 * trap which has not yet been implemented. In the absence of such a trap,
41551 * the enumerability should be checked from the target object; this is
41552 * handled above.
41553 */
41554}
41555#endif /* DUK_USE_ES6_PROXY */
41556
41557#if defined(DUK_USE_ES6_PROXY)
41558DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) {
41559 DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */
41560
41561 duk_require_constructor_call(thr);
41562 duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */
41563 return 1; /* replacement */
41564}
41565#endif /* DUK_USE_ES6_PROXY */
41566#line 1 "duk_bi_reflect.c"
41567/*
41568 * 'Reflect' built-in (ES2016 Section 26.1)
41569 * http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object
41570 *
41571 * Many Reflect built-in functions are provided by shared helpers in
41572 * duk_bi_object.c or duk_bi_function.c.
41573 */
41574
41575/* #include duk_internal.h -> already included */
41576
41577#if defined(DUK_USE_REFLECT_BUILTIN)
41578DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) {
41579 duk_tval *tv_obj;
41580 duk_tval *tv_key;
41581 duk_bool_t ret;
41582
41583 DUK_ASSERT_TOP(thr, 2);
41584 (void) duk_require_hobject(thr, 0);
41585 (void) duk_to_string(thr, 1);
41586
41587 /* [ target key ] */
41588
41589 DUK_ASSERT(thr != NULL);
41590 tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
41591 tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
41592 ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
41593 duk_push_boolean(thr, ret);
41594 return 1;
41595}
41596
41597DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
41598 duk_tval *tv_obj;
41599 duk_tval *tv_key;
41600 duk_idx_t nargs;
41601
41602 DUK_ASSERT(thr != NULL);
41603 nargs = duk_get_top_require_min(thr, 2 /*min_top*/);
41604 (void) duk_require_hobject(thr, 0);
41605 (void) duk_to_string(thr, 1);
41606 if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
41607 /* XXX: [[Get]] receiver currently unsupported */
41608 DUK_ERROR_UNSUPPORTED(thr);
41609 DUK_WO_NORETURN(return 0;);
41610 }
41611
41612 /* [ target key receiver? ...? ] */
41613
41614 tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
41615 tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
41616 (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */
41617 return 1;
41618}
41619
41620DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) {
41621 duk_tval *tv_obj;
41622 duk_tval *tv_key;
41623 duk_bool_t ret;
41624
41625 DUK_ASSERT(thr != NULL);
41626 DUK_ASSERT_TOP(thr, 2);
41627 (void) duk_require_hobject(thr, 0);
41628 (void) duk_to_string(thr, 1);
41629
41630 /* [ target key ] */
41631
41632 tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
41633 tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
41634 ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
41635 duk_push_boolean(thr, ret);
41636 return 1;
41637}
41638
41639DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
41640 duk_tval *tv_obj;
41641 duk_tval *tv_key;
41642 duk_tval *tv_val;
41643 duk_idx_t nargs;
41644 duk_bool_t ret;
41645
41646 DUK_ASSERT(thr != NULL);
41647 nargs = duk_get_top_require_min(thr, 3 /*min_top*/);
41648 (void) duk_require_hobject(thr, 0);
41649 (void) duk_to_string(thr, 1);
41650 if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
41651 /* XXX: [[Set]] receiver currently unsupported */
41652 DUK_ERROR_UNSUPPORTED(thr);
41653 DUK_WO_NORETURN(return 0;);
41654 }
41655
41656 /* [ target key value receiver? ...? ] */
41657
41658 tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
41659 tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
41660 tv_val = DUK_GET_TVAL_POSIDX(thr, 2);
41661 ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
41662 duk_push_boolean(thr, ret);
41663 return 1;
41664}
41665#endif /* DUK_USE_REFLECT_BUILTIN */
41666#line 1 "duk_bi_regexp.c"
41667/*
41668 * RegExp built-ins
41669 */
41670
41671/* #include duk_internal.h -> already included */
41672
41673#if defined(DUK_USE_REGEXP_SUPPORT)
41674
41675DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) {
41676 duk_hobject *h;
41677
41678 duk_push_this(thr);
41679 h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP);
41680 DUK_ASSERT(h != NULL);
41681 DUK_UNREF(h);
41682 duk_insert(thr, 0); /* prepend regexp to valstack 0 index */
41683}
41684
41685/* XXX: much to improve (code size) */
41686DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) {
41687 duk_hobject *h_pattern;
41688
41689 DUK_ASSERT_TOP(thr, 2);
41690 h_pattern = duk_get_hobject(thr, 0);
41691
41692 if (!duk_is_constructor_call(thr) &&
41693 h_pattern != NULL &&
41694 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
41695 duk_is_undefined(thr, 1)) {
41696 /* Called as a function, pattern has [[Class]] "RegExp" and
41697 * flags is undefined -> return object as is.
41698 */
41699 /* XXX: ES2015 has a NewTarget SameValue() check which is not
41700 * yet implemented.
41701 */
41702 duk_dup_0(thr);
41703 return 1;
41704 }
41705
41706 /* Else functionality is identical for function call and constructor
41707 * call.
41708 */
41709
41710 if (h_pattern != NULL &&
41711 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
41712 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE);
41713 if (duk_is_undefined(thr, 1)) {
41714 /* In ES5 one would need to read the flags individually;
41715 * in ES2015 just read .flags.
41716 */
41717 duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
41718 } else {
41719 /* In ES2015 allowed; overrides argument RegExp flags. */
41720 duk_dup_1(thr);
41721 }
41722 } else {
41723 if (duk_is_undefined(thr, 0)) {
41724 duk_push_hstring_empty(thr);
41725 } else {
41726 duk_dup_0(thr);
41727 duk_to_string(thr, -1); /* Rejects Symbols. */
41728 }
41729 if (duk_is_undefined(thr, 1)) {
41730 duk_push_hstring_empty(thr);
41731 } else {
41732 duk_dup_1(thr);
41733 duk_to_string(thr, -1); /* Rejects Symbols. */
41734 }
41735
41736 /* [ ... pattern flags ] */
41737 }
41738
41739 DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
41740 (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
41741
41742 /* [ ... pattern flags ] (both uncoerced) */
41743
41744 duk_to_string(thr, -2);
41745 duk_to_string(thr, -1);
41746 duk_regexp_compile(thr);
41747
41748 /* [ ... bytecode escaped_source ] */
41749
41750 duk_regexp_create_instance(thr);
41751
41752 /* [ ... RegExp ] */
41753
41754 return 1;
41755}
41756
41757DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) {
41758 duk__get_this_regexp(thr);
41759
41760 /* [ regexp input ] */
41761
41762 duk_regexp_match(thr);
41763
41764 /* [ result ] */
41765
41766 return 1;
41767}
41768
41769DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) {
41770 duk__get_this_regexp(thr);
41771
41772 /* [ regexp input ] */
41773
41774 /* result object is created and discarded; wasteful but saves code space */
41775 duk_regexp_match(thr);
41776
41777 /* [ result ] */
41778
41779 duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1));
41780
41781 return 1;
41782}
41783
41784DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
41785 /* This must be generic in ES2015 and later. */
41786 DUK_ASSERT_TOP(thr, 0);
41787 duk_push_this(thr);
41788 duk_push_literal(thr, "/");
41789 duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
41790 duk_dup_m2(thr); /* another "/" */
41791 duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
41792 duk_concat(thr, 4);
41793 return 1;
41794}
41795
41796DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) {
41797 /* .flags is ES2015 but present even when ES2015 bindings are
41798 * disabled because the constructor relies on it.
41799 */
41800 duk_uint8_t buf[8]; /* enough for all flags + NUL */
41801 duk_uint8_t *p = buf;
41802
41803 /* .flags is generic and works on any object. */
41804 duk_push_this(thr);
41805 (void) duk_require_hobject(thr, -1);
41806 if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) {
41807 *p++ = DUK_ASC_LC_G;
41808 }
41809 if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
41810 *p++ = DUK_ASC_LC_I;
41811 }
41812 if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) {
41813 *p++ = DUK_ASC_LC_M;
41814 }
41815 /* .unicode: to be added */
41816 /* .sticky: to be added */
41817 *p++ = DUK_ASC_NUL;
41818 DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
41819
41820 duk_push_string(thr, (const char *) buf);
41821 return 1;
41822}
41823
41824/* Shared helper for providing .source, .global, .multiline, etc getters. */
41825DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
41826 duk_hstring *h_bc;
41827 duk_small_uint_t re_flags;
41828 duk_hobject *h;
41829 duk_int_t magic;
41830
41831 DUK_ASSERT_TOP(thr, 0);
41832
41833 duk_push_this(thr);
41834 h = duk_require_hobject(thr, -1);
41835 magic = duk_get_current_magic(thr);
41836
41837 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
41838 duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE);
41839 duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE);
41840 h_bc = duk_require_hstring(thr, -1);
41841 re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
41842 duk_pop(thr);
41843 } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
41844 /* In ES2015 and ES2016 a TypeError would be thrown here.
41845 * However, this had real world issues so ES2017 draft
41846 * allows RegExp.prototype specifically, returning '(?:)'
41847 * for .source and undefined for all flags.
41848 */
41849 if (magic != 16 /* .source */) {
41850 return 0;
41851 }
41852 duk_push_literal(thr, "(?:)"); /* .source handled by switch-case */
41853 re_flags = 0;
41854 } else {
41855 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
41856 }
41857
41858 /* [ regexp source ] */
41859
41860 switch (magic) {
41861 case 0: { /* global */
41862 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL));
41863 break;
41864 }
41865 case 1: { /* ignoreCase */
41866 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
41867 break;
41868 }
41869 case 2: { /* multiline */
41870 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE));
41871 break;
41872 }
41873#if 0
41874 /* Don't provide until implemented to avoid interfering with feature
41875 * detection in user code.
41876 */
41877 case 3: /* sticky */
41878 case 4: { /* unicode */
41879 duk_push_false(thr);
41880 break;
41881 }
41882#endif
41883 default: { /* source */
41884 /* leave 'source' on top */
41885 break;
41886 }
41887 }
41888
41889 return 1;
41890}
41891
41892#endif /* DUK_USE_REGEXP_SUPPORT */
41893#line 1 "duk_bi_string.c"
41894/*
41895 * String built-ins
41896 *
41897 * Most String built-ins must only accept strings (or String objects).
41898 * Symbols, represented internally as strings, must be generally rejected.
41899 * The duk_push_this_coercible_to_string() helper does this automatically.
41900 */
41901
41902/* XXX: There are several limitations in the current implementation for
41903 * strings with >= 0x80000000UL characters. In some cases one would need
41904 * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
41905 * Generally character and byte length are assumed to fit into signed 32
41906 * bits (< 0x80000000UL). Places with issues are not marked explicitly
41907 * below in all cases, look for signed type usage (duk_int_t etc) for
41908 * offsets/lengths.
41909 */
41910
41911/* #include duk_internal.h -> already included */
41912
41913#if defined(DUK_USE_STRING_BUILTIN)
41914
41915/*
41916 * Helpers
41917 */
41918
41919DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) {
41920 duk_hstring *h;
41921
41922 if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) {
41923 DUK_ERROR_TYPE_INVALID_ARGS(thr);
41924 DUK_WO_NORETURN(return NULL;);
41925 }
41926 h = duk_to_hstring(thr, idx);
41927 DUK_ASSERT(h != NULL);
41928
41929 return h;
41930}
41931
41932DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) {
41933 duk_int_t cpos;
41934 duk_int_t bpos;
41935 const duk_uint8_t *p_start, *p_end, *p;
41936 const duk_uint8_t *q_start;
41937 duk_int_t q_blen;
41938 duk_uint8_t firstbyte;
41939 duk_uint8_t t;
41940
41941 cpos = start_cpos;
41942
41943 /* Empty searchstring always matches; cpos must be clamped here.
41944 * (If q_blen were < 0 due to clamped coercion, it would also be
41945 * caught here.)
41946 */
41947 q_start = DUK_HSTRING_GET_DATA(h_search);
41948 q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
41949 if (q_blen <= 0) {
41950 return cpos;
41951 }
41952 DUK_ASSERT(q_blen > 0);
41953
41954 bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
41955
41956 p_start = DUK_HSTRING_GET_DATA(h_this);
41957 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
41958 p = p_start + bpos;
41959
41960 /* This loop is optimized for size. For speed, there should be
41961 * two separate loops, and we should ensure that memcmp() can be
41962 * used without an extra "will searchstring fit" check. Doing
41963 * the preconditioning for 'p' and 'p_end' is easy but cpos
41964 * must be updated if 'p' is wound back (backward scanning).
41965 */
41966
41967 firstbyte = q_start[0]; /* leading byte of match string */
41968 while (p <= p_end && p >= p_start) {
41969 t = *p;
41970
41971 /* For ECMAScript strings, this check can only match for
41972 * initial UTF-8 bytes (not continuation bytes). For other
41973 * strings all bets are off.
41974 */
41975
41976 if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
41977 DUK_ASSERT(q_blen > 0);
41978 if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
41979 return cpos;
41980 }
41981 }
41982
41983 /* track cpos while scanning */
41984 if (backwards) {
41985 /* when going backwards, we decrement cpos 'early';
41986 * 'p' may point to a continuation byte of the char
41987 * at offset 'cpos', but that's OK because we'll
41988 * backtrack all the way to the initial byte.
41989 */
41990 if ((t & 0xc0) != 0x80) {
41991 cpos--;
41992 }
41993 p--;
41994 } else {
41995 if ((t & 0xc0) != 0x80) {
41996 cpos++;
41997 }
41998 p++;
41999 }
42000 }
42001
42002 /* Not found. Empty string case is handled specially above. */
42003 return -1;
42004}
42005
42006/*
42007 * Constructor
42008 */
42009
42010DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) {
42011 duk_hstring *h;
42012 duk_uint_t flags;
42013
42014 /* String constructor needs to distinguish between an argument not given at all
42015 * vs. given as 'undefined'. We're a vararg function to handle this properly.
42016 */
42017
42018 /* XXX: copy current activation flags to thr, including current magic,
42019 * is_constructor_call etc. This takes a few bytes in duk_hthread but
42020 * makes call sites smaller (there are >30 is_constructor_call and get
42021 * current magic call sites.
42022 */
42023
42024 if (duk_get_top(thr) == 0) {
42025 duk_push_hstring_empty(thr);
42026 } else {
42027 h = duk_to_hstring_acceptsymbol(thr, 0);
42028 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) {
42029 duk_push_symbol_descriptive_string(thr, h);
42030 duk_replace(thr, 0);
42031 }
42032 }
42033 duk_to_string(thr, 0); /* catches symbol argument for constructor call */
42034 DUK_ASSERT(duk_is_string(thr, 0));
42035 duk_set_top(thr, 1); /* Top may be 1 or larger. */
42036
42037 if (duk_is_constructor_call(thr)) {
42038 /* String object internal value is immutable */
42039 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
42040 DUK_HOBJECT_FLAG_FASTREFS |
42041 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
42042 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
42043 duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE);
42044 duk_dup_0(thr);
42045 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
42046 }
42047 /* Note: unbalanced stack on purpose */
42048
42049 return 1;
42050}
42051
42052DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) {
42053 duk_bufwriter_ctx bw_alloc;
42054 duk_bufwriter_ctx *bw;
42055 duk_idx_t i, n;
42056 duk_ucodepoint_t cp;
42057
42058 /* XXX: It would be nice to build the string directly but ToUint16()
42059 * coercion is needed so a generic helper would not be very
42060 * helpful (perhaps coerce the value stack first here and then
42061 * build a string from a duk_tval number sequence in one go?).
42062 */
42063
42064 n = duk_get_top(thr);
42065
42066 bw = &bw_alloc;
42067 DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n); /* initial estimate for ASCII only codepoints */
42068
42069 for (i = 0; i < n; i++) {
42070 /* XXX: could improve bufwriter handling to write multiple codepoints
42071 * with one ensure call but the relative benefit would be quite small.
42072 */
42073
42074 if (nonbmp) {
42075 /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and
42076 * (2) cp >= 0 and cp <= 0x10ffff. This check does not
42077 * implement the steps exactly but the outcome should be
42078 * the same.
42079 */
42080 duk_int32_t i32 = 0;
42081 if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) ||
42082 i32 < 0 || i32 > 0x10ffffL) {
42083 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
42084 }
42085 DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL);
42086 cp = (duk_ucodepoint_t) i32;
42087 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
42088 } else {
42089#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
42090 /* ToUint16() coercion is mandatory in the E5.1 specification, but
42091 * this non-compliant behavior makes more sense because we support
42092 * non-BMP codepoints. Don't use CESU-8 because that'd create
42093 * surrogate pairs.
42094 */
42095 cp = (duk_ucodepoint_t) duk_to_uint32(thr, i);
42096 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
42097#else
42098 cp = (duk_ucodepoint_t) duk_to_uint16(thr, i);
42099 DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL);
42100 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
42101#endif
42102 }
42103 }
42104
42105 DUK_BW_COMPACT(thr, bw);
42106 (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */
42107 return 1;
42108}
42109
42110DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) {
42111 return duk__construct_from_codepoints(thr, 0 /*nonbmp*/);
42112}
42113
42114#if defined(DUK_USE_ES6)
42115DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) {
42116 return duk__construct_from_codepoints(thr, 1 /*nonbmp*/);
42117}
42118#endif
42119
42120/*
42121 * toString(), valueOf()
42122 */
42123
42124DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) {
42125 duk_tval *tv;
42126
42127 duk_push_this(thr);
42128 tv = duk_require_tval(thr, -1);
42129 DUK_ASSERT(tv != NULL);
42130
42131 if (DUK_TVAL_IS_STRING(tv)) {
42132 /* return as is */
42133 } else if (DUK_TVAL_IS_OBJECT(tv)) {
42134 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
42135 DUK_ASSERT(h != NULL);
42136
42137 /* Must be a "string object", i.e. class "String" */
42138 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
42139 goto type_error;
42140 }
42141
42142 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
42143 DUK_ASSERT(duk_is_string(thr, -1));
42144 } else {
42145 goto type_error;
42146 }
42147
42148 (void) duk_require_hstring_notsymbol(thr, -1); /* Reject symbols (and wrapped symbols). */
42149 return 1;
42150
42151 type_error:
42152 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
42153}
42154
42155/*
42156 * Character and charcode access
42157 */
42158
42159DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) {
42160 duk_hstring *h;
42161 duk_int_t pos;
42162
42163 /* XXX: faster implementation */
42164
42165 h = duk_push_this_coercible_to_string(thr);
42166 DUK_ASSERT(h != NULL);
42167
42168 pos = duk_to_int(thr, 0);
42169
42170 if (sizeof(duk_size_t) >= sizeof(duk_uint_t)) {
42171 /* Cast to duk_size_t works in this case:
42172 * - If pos < 0, (duk_size_t) pos will always be
42173 * >= max_charlen, and result will be the empty string
42174 * (see duk_substring()).
42175 * - If pos >= 0, pos + 1 cannot wrap.
42176 */
42177 DUK_ASSERT((duk_size_t) DUK_INT_MIN >= DUK_HSTRING_MAX_BYTELEN);
42178 DUK_ASSERT((duk_size_t) DUK_INT_MAX + 1U > (duk_size_t) DUK_INT_MAX);
42179 duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
42180 } else {
42181 /* If size_t is smaller than int, explicit bounds checks
42182 * are needed because an int may wrap multiple times.
42183 */
42184 if (DUK_UNLIKELY(pos < 0 || (duk_uint_t) pos >= (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h))) {
42185 duk_push_hstring_empty(thr);
42186 } else {
42187 duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
42188 }
42189 }
42190
42191 return 1;
42192}
42193
42194/* Magic: 0=charCodeAt, 1=codePointAt */
42195DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) {
42196 duk_int_t pos;
42197 duk_hstring *h;
42198 duk_bool_t clamped;
42199 duk_uint32_t cp;
42200 duk_int_t magic;
42201
42202 /* XXX: faster implementation */
42203
42204 DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(thr, 0)));
42205
42206 h = duk_push_this_coercible_to_string(thr);
42207 DUK_ASSERT(h != NULL);
42208
42209 pos = duk_to_int_clamped_raw(thr,
42210 0 /*index*/,
42211 0 /*min(incl)*/,
42212 (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
42213 &clamped /*out_clamped*/);
42214#if defined(DUK_USE_ES6)
42215 magic = duk_get_current_magic(thr);
42216#else
42217 DUK_ASSERT(duk_get_current_magic(thr) == 0);
42218 magic = 0;
42219#endif
42220 if (clamped) {
42221 /* For out-of-bounds indices .charCodeAt() returns NaN and
42222 * .codePointAt() returns undefined.
42223 */
42224 if (magic != 0) {
42225 return 0;
42226 }
42227 duk_push_nan(thr);
42228 } else {
42229 DUK_ASSERT(pos >= 0);
42230 cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/);
42231 duk_push_u32(thr, cp);
42232 }
42233 return 1;
42234}
42235
42236/*
42237 * substring(), substr(), slice()
42238 */
42239
42240/* XXX: any chance of merging these three similar but still slightly
42241 * different algorithms so that footprint would be reduced?
42242 */
42243
42244DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) {
42245 duk_hstring *h;
42246 duk_int_t start_pos, end_pos;
42247 duk_int_t len;
42248
42249 h = duk_push_this_coercible_to_string(thr);
42250 DUK_ASSERT(h != NULL);
42251 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
42252
42253 /* [ start end str ] */
42254
42255 start_pos = duk_to_int_clamped(thr, 0, 0, len);
42256 if (duk_is_undefined(thr, 1)) {
42257 end_pos = len;
42258 } else {
42259 end_pos = duk_to_int_clamped(thr, 1, 0, len);
42260 }
42261 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
42262 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
42263
42264 if (start_pos > end_pos) {
42265 duk_int_t tmp = start_pos;
42266 start_pos = end_pos;
42267 end_pos = tmp;
42268 }
42269
42270 DUK_ASSERT(end_pos >= start_pos);
42271
42272 duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
42273 return 1;
42274}
42275
42276#if defined(DUK_USE_SECTION_B)
42277DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) {
42278 duk_hstring *h;
42279 duk_int_t start_pos, end_pos;
42280 duk_int_t len;
42281
42282 /* Unlike non-obsolete String calls, substr() algorithm in E5.1
42283 * specification will happily coerce undefined and null to strings
42284 * ("undefined" and "null").
42285 */
42286 duk_push_this(thr);
42287 h = duk_to_hstring_m1(thr); /* Reject Symbols. */
42288 DUK_ASSERT(h != NULL);
42289 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
42290
42291 /* [ start length str ] */
42292
42293 /* The implementation for computing of start_pos and end_pos differs
42294 * from the standard algorithm, but is intended to result in the exactly
42295 * same behavior. This is not always obvious.
42296 */
42297
42298 /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
42299 start_pos = duk_to_int_clamped(thr, 0, -len, len);
42300 if (start_pos < 0) {
42301 start_pos = len + start_pos;
42302 }
42303 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
42304
42305 /* combines steps 3, 6; step 7 is not needed */
42306 if (duk_is_undefined(thr, 1)) {
42307 end_pos = len;
42308 } else {
42309 DUK_ASSERT(start_pos <= len);
42310 end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos);
42311 }
42312 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
42313 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
42314 DUK_ASSERT(end_pos >= start_pos);
42315
42316 duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
42317 return 1;
42318}
42319#endif /* DUK_USE_SECTION_B */
42320
42321DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) {
42322 duk_hstring *h;
42323 duk_int_t start_pos, end_pos;
42324 duk_int_t len;
42325
42326 h = duk_push_this_coercible_to_string(thr);
42327 DUK_ASSERT(h != NULL);
42328 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
42329
42330 /* [ start end str ] */
42331
42332 start_pos = duk_to_int_clamped(thr, 0, -len, len);
42333 if (start_pos < 0) {
42334 start_pos = len + start_pos;
42335 }
42336 if (duk_is_undefined(thr, 1)) {
42337 end_pos = len;
42338 } else {
42339 end_pos = duk_to_int_clamped(thr, 1, -len, len);
42340 if (end_pos < 0) {
42341 end_pos = len + end_pos;
42342 }
42343 }
42344 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
42345 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
42346
42347 if (end_pos < start_pos) {
42348 end_pos = start_pos;
42349 }
42350
42351 DUK_ASSERT(end_pos >= start_pos);
42352
42353 duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
42354 return 1;
42355}
42356
42357/*
42358 * Case conversion
42359 */
42360
42361DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) {
42362 duk_small_int_t uppercase = duk_get_current_magic(thr);
42363
42364 (void) duk_push_this_coercible_to_string(thr);
42365 duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
42366 return 1;
42367}
42368
42369/*
42370 * indexOf() and lastIndexOf()
42371 */
42372
42373DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) {
42374 duk_hstring *h_this;
42375 duk_hstring *h_search;
42376 duk_int_t clen_this;
42377 duk_int_t cpos;
42378 duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr); /* 0=indexOf, 1=lastIndexOf */
42379
42380 h_this = duk_push_this_coercible_to_string(thr);
42381 DUK_ASSERT(h_this != NULL);
42382 clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
42383
42384 h_search = duk_to_hstring(thr, 0);
42385 DUK_ASSERT(h_search != NULL);
42386
42387 duk_to_number(thr, 1);
42388 if (duk_is_nan(thr, 1) && is_lastindexof) {
42389 /* indexOf: NaN should cause pos to be zero.
42390 * lastIndexOf: NaN should cause pos to be +Infinity
42391 * (and later be clamped to len).
42392 */
42393 cpos = clen_this;
42394 } else {
42395 cpos = duk_to_int_clamped(thr, 1, 0, clen_this);
42396 }
42397
42398 cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/);
42399 duk_push_int(thr, cpos);
42400 return 1;
42401}
42402
42403/*
42404 * replace()
42405 */
42406
42407/* XXX: the current implementation works but is quite clunky; it compiles
42408 * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
42409 * shared helpers, etc). Some ideas for refactoring:
42410 *
42411 * - a primitive to convert a string into a regexp matcher (reduces matching
42412 * code at the cost of making matching much slower)
42413 * - use replace() as a basic helper for match() and split(), which are both
42414 * much simpler
42415 * - API call to get_prop and to_boolean
42416 */
42417
42418DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) {
42419 duk_hstring *h_input;
42420 duk_hstring *h_match;
42421 duk_hstring *h_search;
42422 duk_hobject *h_re;
42423 duk_bufwriter_ctx bw_alloc;
42424 duk_bufwriter_ctx *bw;
42425#if defined(DUK_USE_REGEXP_SUPPORT)
42426 duk_bool_t is_regexp;
42427 duk_bool_t is_global;
42428#endif
42429 duk_bool_t is_repl_func;
42430 duk_uint32_t match_start_coff, match_start_boff;
42431#if defined(DUK_USE_REGEXP_SUPPORT)
42432 duk_int_t match_caps;
42433#endif
42434 duk_uint32_t prev_match_end_boff;
42435 const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
42436 duk_size_t tmp_sz;
42437
42438 DUK_ASSERT_TOP(thr, 2);
42439 h_input = duk_push_this_coercible_to_string(thr);
42440 DUK_ASSERT(h_input != NULL);
42441
42442 bw = &bw_alloc;
42443 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
42444
42445 DUK_ASSERT_TOP(thr, 4);
42446
42447 /* stack[0] = search value
42448 * stack[1] = replace value
42449 * stack[2] = input string
42450 * stack[3] = result buffer
42451 */
42452
42453 h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP);
42454 if (h_re) {
42455#if defined(DUK_USE_REGEXP_SUPPORT)
42456 is_regexp = 1;
42457 is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
42458
42459 if (is_global) {
42460 /* start match from beginning */
42461 duk_push_int(thr, 0);
42462 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
42463 }
42464#else /* DUK_USE_REGEXP_SUPPORT */
42465 DUK_DCERROR_UNSUPPORTED(thr);
42466#endif /* DUK_USE_REGEXP_SUPPORT */
42467 } else {
42468 duk_to_string(thr, 0); /* rejects symbols */
42469#if defined(DUK_USE_REGEXP_SUPPORT)
42470 is_regexp = 0;
42471 is_global = 0;
42472#endif
42473 }
42474
42475 if (duk_is_function(thr, 1)) {
42476 is_repl_func = 1;
42477 r_start = NULL;
42478 r_end = NULL;
42479 } else {
42480 duk_hstring *h_repl;
42481
42482 is_repl_func = 0;
42483 h_repl = duk_to_hstring(thr, 1); /* reject symbols */
42484 DUK_ASSERT(h_repl != NULL);
42485 r_start = DUK_HSTRING_GET_DATA(h_repl);
42486 r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
42487 }
42488
42489 prev_match_end_boff = 0;
42490
42491 for (;;) {
42492 /*
42493 * If matching with a regexp:
42494 * - non-global RegExp: lastIndex not touched on a match, zeroed
42495 * on a non-match
42496 * - global RegExp: on match, lastIndex will be updated by regexp
42497 * executor to point to next char after the matching part (so that
42498 * characters in the matching part are not matched again)
42499 *
42500 * If matching with a string:
42501 * - always non-global match, find first occurrence
42502 *
42503 * We need:
42504 * - The character offset of start-of-match for the replacer function
42505 * - The byte offsets for start-of-match and end-of-match to implement
42506 * the replacement values $&, $`, and $', and to copy non-matching
42507 * input string portions (including header and trailer) verbatim.
42508 *
42509 * NOTE: the E5.1 specification is a bit vague how the RegExp should
42510 * behave in the replacement process; e.g. is matching done first for
42511 * all matches (in the global RegExp case) before any replacer calls
42512 * are made? See: test-bi-string-proto-replace.js for discussion.
42513 */
42514
42515 DUK_ASSERT_TOP(thr, 4);
42516
42517#if defined(DUK_USE_REGEXP_SUPPORT)
42518 if (is_regexp) {
42519 duk_dup_0(thr);
42520 duk_dup_2(thr);
42521 duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
42522 if (!duk_is_object(thr, -1)) {
42523 duk_pop(thr);
42524 break;
42525 }
42526
42527 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
42528 DUK_ASSERT(duk_is_number(thr, -1));
42529 match_start_coff = duk_get_uint(thr, -1);
42530 duk_pop(thr);
42531
42532 duk_get_prop_index(thr, -1, 0);
42533 DUK_ASSERT(duk_is_string(thr, -1));
42534 h_match = duk_known_hstring(thr, -1);
42535 duk_pop(thr); /* h_match is borrowed, remains reachable through match_obj */
42536
42537 if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
42538 /* This should be equivalent to match() algorithm step 8.f.iii.2:
42539 * detect an empty match and allow it, but don't allow it twice.
42540 */
42541 duk_uint32_t last_index;
42542
42543 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
42544 last_index = (duk_uint32_t) duk_get_uint(thr, -1);
42545 DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
42546 (long) last_index, (long) (last_index + 1)));
42547 duk_pop(thr);
42548 duk_push_uint(thr, (duk_uint_t) (last_index + 1));
42549 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
42550 }
42551
42552 DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX); /* string limits */
42553 match_caps = (duk_int_t) duk_get_length(thr, -1);
42554 } else {
42555#else /* DUK_USE_REGEXP_SUPPORT */
42556 { /* unconditionally */
42557#endif /* DUK_USE_REGEXP_SUPPORT */
42558 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
42559 const duk_uint8_t *q_start; /* match string */
42560 duk_size_t p_blen;
42561 duk_size_t q_blen;
42562
42563#if defined(DUK_USE_REGEXP_SUPPORT)
42564 DUK_ASSERT(!is_global); /* single match always */
42565#endif
42566
42567 p_start = DUK_HSTRING_GET_DATA(h_input);
42568 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
42569 p_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_input);
42570 p = p_start;
42571
42572 h_search = duk_known_hstring(thr, 0);
42573 q_start = DUK_HSTRING_GET_DATA(h_search);
42574 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
42575
42576 if (q_blen > p_blen) {
42577 break; /* no match */
42578 }
42579
42580 p_end -= q_blen; /* ensure full memcmp() fits in while */
42581 DUK_ASSERT(p_end >= p);
42582
42583 match_start_coff = 0;
42584
42585 while (p <= p_end) {
42586 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
42587 if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
42588 duk_dup_0(thr);
42589 h_match = duk_known_hstring(thr, -1);
42590#if defined(DUK_USE_REGEXP_SUPPORT)
42591 match_caps = 0;
42592#endif
42593 goto found;
42594 }
42595
42596 /* track utf-8 non-continuation bytes */
42597 if ((p[0] & 0xc0) != 0x80) {
42598 match_start_coff++;
42599 }
42600 p++;
42601 }
42602
42603 /* not found */
42604 break;
42605 }
42606 found:
42607
42608 /* stack[0] = search value
42609 * stack[1] = replace value
42610 * stack[2] = input string
42611 * stack[3] = result buffer
42612 * stack[4] = regexp match OR match string
42613 */
42614
42615 match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
42616
42617 tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
42618 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
42619
42620 prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
42621
42622 if (is_repl_func) {
42623 duk_idx_t idx_args;
42624 duk_hstring *h_repl;
42625
42626 /* regexp res_obj is at index 4 */
42627
42628 duk_dup_1(thr);
42629 idx_args = duk_get_top(thr);
42630
42631#if defined(DUK_USE_REGEXP_SUPPORT)
42632 if (is_regexp) {
42633 duk_int_t idx;
42634 duk_require_stack(thr, match_caps + 2);
42635 for (idx = 0; idx < match_caps; idx++) {
42636 /* match followed by capture(s) */
42637 duk_get_prop_index(thr, 4, (duk_uarridx_t) idx);
42638 }
42639 } else {
42640#else /* DUK_USE_REGEXP_SUPPORT */
42641 { /* unconditionally */
42642#endif /* DUK_USE_REGEXP_SUPPORT */
42643 /* match == search string, by definition */
42644 duk_dup_0(thr);
42645 }
42646 duk_push_uint(thr, (duk_uint_t) match_start_coff);
42647 duk_dup_2(thr);
42648
42649 /* [ ... replacer match [captures] match_char_offset input ] */
42650
42651 duk_call(thr, duk_get_top(thr) - idx_args);
42652 h_repl = duk_to_hstring_m1(thr); /* -> [ ... repl_value ] */
42653 DUK_ASSERT(h_repl != NULL);
42654
42655 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
42656
42657 duk_pop(thr); /* repl_value */
42658 } else {
42659 r = r_start;
42660
42661 while (r < r_end) {
42662 duk_int_t ch1;
42663 duk_int_t ch2;
42664#if defined(DUK_USE_REGEXP_SUPPORT)
42665 duk_int_t ch3;
42666#endif
42667 duk_size_t left;
42668
42669 ch1 = *r++;
42670 if (ch1 != DUK_ASC_DOLLAR) {
42671 goto repl_write;
42672 }
42673 DUK_ASSERT(r <= r_end);
42674 left = (duk_size_t) (r_end - r);
42675
42676 if (left <= 0) {
42677 goto repl_write;
42678 }
42679
42680 ch2 = r[0];
42681 switch (ch2) {
42682 case DUK_ASC_DOLLAR: {
42683 ch1 = (1 << 8) + DUK_ASC_DOLLAR;
42684 goto repl_write;
42685 }
42686 case DUK_ASC_AMP: {
42687 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
42688 r++;
42689 continue;
42690 }
42691 case DUK_ASC_GRAVE: {
42692 tmp_sz = (duk_size_t) match_start_boff;
42693 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
42694 r++;
42695 continue;
42696 }
42697 case DUK_ASC_SINGLEQUOTE: {
42698 duk_uint32_t match_end_boff;
42699
42700 /* Use match charlen instead of bytelen, just in case the input and
42701 * match codepoint encodings would have different lengths.
42702 */
42703 /* XXX: charlen computed here, and also in char2byte helper. */
42704 match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr,
42705 h_input,
42706 match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match));
42707
42708 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
42709 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
42710 r++;
42711 continue;
42712 }
42713 default: {
42714#if defined(DUK_USE_REGEXP_SUPPORT)
42715 duk_int_t capnum, captmp, capadv;
42716 /* XXX: optional check, match_caps is zero if no regexp,
42717 * so dollar will be interpreted literally anyway.
42718 */
42719
42720 if (!is_regexp) {
42721 goto repl_write;
42722 }
42723
42724 if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
42725 goto repl_write;
42726 }
42727 capnum = ch2 - DUK_ASC_0;
42728 capadv = 1;
42729
42730 if (left >= 2) {
42731 ch3 = r[1];
42732 if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
42733 captmp = capnum * 10 + (ch3 - DUK_ASC_0);
42734 if (captmp < match_caps) {
42735 capnum = captmp;
42736 capadv = 2;
42737 }
42738 }
42739 }
42740
42741 if (capnum > 0 && capnum < match_caps) {
42742 DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
42743
42744 /* regexp res_obj is at offset 4 */
42745 duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum);
42746 if (duk_is_string(thr, -1)) {
42747 duk_hstring *h_tmp_str;
42748
42749 h_tmp_str = duk_known_hstring(thr, -1);
42750
42751 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
42752 } else {
42753 /* undefined -> skip (replaced with empty) */
42754 }
42755 duk_pop(thr);
42756 r += capadv;
42757 continue;
42758 } else {
42759 goto repl_write;
42760 }
42761#else /* DUK_USE_REGEXP_SUPPORT */
42762 goto repl_write; /* unconditionally */
42763#endif /* DUK_USE_REGEXP_SUPPORT */
42764 } /* default case */
42765 } /* switch (ch2) */
42766
42767 repl_write:
42768 /* ch1 = (r_increment << 8) + byte */
42769
42770 DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
42771 r += ch1 >> 8;
42772 } /* while repl */
42773 } /* if (is_repl_func) */
42774
42775 duk_pop(thr); /* pop regexp res_obj or match string */
42776
42777#if defined(DUK_USE_REGEXP_SUPPORT)
42778 if (!is_global) {
42779#else
42780 { /* unconditionally; is_global==0 */
42781#endif
42782 break;
42783 }
42784 }
42785
42786 /* trailer */
42787 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
42788 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
42789
42790 DUK_ASSERT_TOP(thr, 4);
42791 DUK_BW_COMPACT(thr, bw);
42792 (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
42793 return 1;
42794}
42795
42796/*
42797 * split()
42798 */
42799
42800/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
42801 * used so compiler doesn't complain).
42802 */
42803
42804DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) {
42805 duk_hstring *h_input;
42806 duk_hstring *h_sep;
42807 duk_uint32_t limit;
42808 duk_uint32_t arr_idx;
42809#if defined(DUK_USE_REGEXP_SUPPORT)
42810 duk_bool_t is_regexp;
42811#endif
42812 duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
42813 duk_uint32_t prev_match_end_coff, prev_match_end_boff;
42814 duk_uint32_t match_start_boff, match_start_coff;
42815 duk_uint32_t match_end_boff, match_end_coff;
42816
42817 h_input = duk_push_this_coercible_to_string(thr);
42818 DUK_ASSERT(h_input != NULL);
42819
42820 duk_push_array(thr);
42821
42822 if (duk_is_undefined(thr, 1)) {
42823 limit = 0xffffffffUL;
42824 } else {
42825 limit = duk_to_uint32(thr, 1);
42826 }
42827
42828 if (limit == 0) {
42829 return 1;
42830 }
42831
42832 /* If the separator is a RegExp, make a "clone" of it. The specification
42833 * algorithm calls [[Match]] directly for specific indices; we emulate this
42834 * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
42835 * which will use global-style matching even when the RegExp itself is non-global.
42836 */
42837
42838 if (duk_is_undefined(thr, 0)) {
42839 /* The spec algorithm first does "R = ToString(separator)" before checking
42840 * whether separator is undefined. Since this is side effect free, we can
42841 * skip the ToString() here.
42842 */
42843 duk_dup_2(thr);
42844 duk_put_prop_index(thr, 3, 0);
42845 return 1;
42846 } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
42847#if defined(DUK_USE_REGEXP_SUPPORT)
42848 duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
42849 duk_dup_0(thr);
42850 duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
42851 duk_replace(thr, 0);
42852 /* lastIndex is initialized to zero by new RegExp() */
42853 is_regexp = 1;
42854#else
42855 DUK_DCERROR_UNSUPPORTED(thr);
42856#endif
42857 } else {
42858 duk_to_string(thr, 0);
42859#if defined(DUK_USE_REGEXP_SUPPORT)
42860 is_regexp = 0;
42861#endif
42862 }
42863
42864 /* stack[0] = separator (string or regexp)
42865 * stack[1] = limit
42866 * stack[2] = input string
42867 * stack[3] = result array
42868 */
42869
42870 prev_match_end_boff = 0;
42871 prev_match_end_coff = 0;
42872 arr_idx = 0;
42873 matched = 0;
42874
42875 for (;;) {
42876 /*
42877 * The specification uses RegExp [[Match]] to attempt match at specific
42878 * offsets. We don't have such a primitive, so we use an actual RegExp
42879 * and tweak lastIndex. Since the RegExp may be non-global, we use a
42880 * special variant which forces global-like behavior for matching.
42881 */
42882
42883 DUK_ASSERT_TOP(thr, 4);
42884
42885#if defined(DUK_USE_REGEXP_SUPPORT)
42886 if (is_regexp) {
42887 duk_dup_0(thr);
42888 duk_dup_2(thr);
42889 duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
42890 if (!duk_is_object(thr, -1)) {
42891 duk_pop(thr);
42892 break;
42893 }
42894 matched = 1;
42895
42896 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
42897 DUK_ASSERT(duk_is_number(thr, -1));
42898 match_start_coff = duk_get_uint(thr, -1);
42899 match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
42900 duk_pop(thr);
42901
42902 if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
42903 /* don't allow an empty match at the end of the string */
42904 duk_pop(thr);
42905 break;
42906 }
42907
42908 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
42909 DUK_ASSERT(duk_is_number(thr, -1));
42910 match_end_coff = duk_get_uint(thr, -1);
42911 match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
42912 duk_pop(thr);
42913
42914 /* empty match -> bump and continue */
42915 if (prev_match_end_boff == match_end_boff) {
42916 duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1));
42917 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
42918 duk_pop(thr);
42919 continue;
42920 }
42921 } else {
42922#else /* DUK_USE_REGEXP_SUPPORT */
42923 { /* unconditionally */
42924#endif /* DUK_USE_REGEXP_SUPPORT */
42925 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
42926 const duk_uint8_t *q_start; /* match string */
42927 duk_size_t q_blen, q_clen;
42928
42929 p_start = DUK_HSTRING_GET_DATA(h_input);
42930 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
42931 p = p_start + prev_match_end_boff;
42932
42933 h_sep = duk_known_hstring(thr, 0); /* symbol already rejected above */
42934 q_start = DUK_HSTRING_GET_DATA(h_sep);
42935 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
42936 q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
42937
42938 p_end -= q_blen; /* ensure full memcmp() fits in while */
42939
42940 match_start_coff = prev_match_end_coff;
42941
42942 if (q_blen == 0) {
42943 /* Handle empty separator case: it will always match, and always
42944 * triggers the check in step 13.c.iii initially. Note that we
42945 * must skip to either end of string or start of first codepoint,
42946 * skipping over any continuation bytes!
42947 *
42948 * Don't allow an empty string to match at the end of the input.
42949 */
42950
42951 matched = 1; /* empty separator can always match */
42952
42953 match_start_coff++;
42954 p++;
42955 while (p < p_end) {
42956 if ((p[0] & 0xc0) != 0x80) {
42957 goto found;
42958 }
42959 p++;
42960 }
42961 goto not_found;
42962 }
42963
42964 DUK_ASSERT(q_blen > 0 && q_clen > 0);
42965 while (p <= p_end) {
42966 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
42967 DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
42968 if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
42969 /* never an empty match, so step 13.c.iii can't be triggered */
42970 goto found;
42971 }
42972
42973 /* track utf-8 non-continuation bytes */
42974 if ((p[0] & 0xc0) != 0x80) {
42975 match_start_coff++;
42976 }
42977 p++;
42978 }
42979
42980 not_found:
42981 /* not found */
42982 break;
42983
42984 found:
42985 matched = 1;
42986 match_start_boff = (duk_uint32_t) (p - p_start);
42987 match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */
42988 match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */
42989
42990 /* empty match (may happen with empty separator) -> bump and continue */
42991 if (prev_match_end_boff == match_end_boff) {
42992 prev_match_end_boff++;
42993 prev_match_end_coff++;
42994 continue;
42995 }
42996 } /* if (is_regexp) */
42997
42998 /* stack[0] = separator (string or regexp)
42999 * stack[1] = limit
43000 * stack[2] = input string
43001 * stack[3] = result array
43002 * stack[4] = regexp res_obj (if is_regexp)
43003 */
43004
43005 DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
43006 (long) match_start_boff, (long) match_start_coff,
43007 (long) match_end_boff, (long) match_end_coff,
43008 (long) prev_match_end_boff, (long) prev_match_end_coff));
43009
43010 duk_push_lstring(thr,
43011 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
43012 (duk_size_t) (match_start_boff - prev_match_end_boff));
43013 duk_put_prop_index(thr, 3, arr_idx);
43014 arr_idx++;
43015 if (arr_idx >= limit) {
43016 goto hit_limit;
43017 }
43018
43019#if defined(DUK_USE_REGEXP_SUPPORT)
43020 if (is_regexp) {
43021 duk_size_t i, len;
43022
43023 len = duk_get_length(thr, 4);
43024 for (i = 1; i < len; i++) {
43025 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
43026 duk_get_prop_index(thr, 4, (duk_uarridx_t) i);
43027 duk_put_prop_index(thr, 3, arr_idx);
43028 arr_idx++;
43029 if (arr_idx >= limit) {
43030 goto hit_limit;
43031 }
43032 }
43033
43034 duk_pop(thr);
43035 /* lastIndex already set up for next match */
43036 } else {
43037#else /* DUK_USE_REGEXP_SUPPORT */
43038 { /* unconditionally */
43039#endif /* DUK_USE_REGEXP_SUPPORT */
43040 /* no action */
43041 }
43042
43043 prev_match_end_boff = match_end_boff;
43044 prev_match_end_coff = match_end_coff;
43045 continue;
43046 } /* for */
43047
43048 /* Combined step 11 (empty string special case) and 14-15. */
43049
43050 DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
43051 (long) prev_match_end_boff, (long) prev_match_end_coff));
43052
43053 if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) {
43054 /* Add trailer if:
43055 * a) non-empty input
43056 * b) empty input and no (zero size) match found (step 11)
43057 */
43058
43059 duk_push_lstring(thr,
43060 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
43061 (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
43062 duk_put_prop_index(thr, 3, arr_idx);
43063 /* No arr_idx update or limit check */
43064 }
43065
43066 return 1;
43067
43068 hit_limit:
43069#if defined(DUK_USE_REGEXP_SUPPORT)
43070 if (is_regexp) {
43071 duk_pop(thr);
43072 }
43073#endif
43074
43075 return 1;
43076}
43077
43078/*
43079 * Various
43080 */
43081
43082#if defined(DUK_USE_REGEXP_SUPPORT)
43083DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) {
43084 duk_hobject *h;
43085
43086 /* Shared helper for match() steps 3-4, search() steps 3-4. */
43087
43088 DUK_ASSERT(idx >= 0);
43089
43090 if (force_new) {
43091 goto do_new;
43092 }
43093
43094 h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP);
43095 if (!h) {
43096 goto do_new;
43097 }
43098 return;
43099
43100 do_new:
43101 duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
43102 duk_dup(thr, idx);
43103 duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */
43104 duk_replace(thr, idx);
43105}
43106#endif /* DUK_USE_REGEXP_SUPPORT */
43107
43108#if defined(DUK_USE_REGEXP_SUPPORT)
43109DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) {
43110 /* Easiest way to implement the search required by the specification
43111 * is to do a RegExp test() with lastIndex forced to zero. To avoid
43112 * side effects on the argument, "clone" the RegExp if a RegExp was
43113 * given as input.
43114 *
43115 * The global flag of the RegExp should be ignored; setting lastIndex
43116 * to zero (which happens when "cloning" the RegExp) should have an
43117 * equivalent effect.
43118 */
43119
43120 DUK_ASSERT_TOP(thr, 1);
43121 (void) duk_push_this_coercible_to_string(thr); /* at index 1 */
43122 duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/);
43123
43124 /* stack[0] = regexp
43125 * stack[1] = string
43126 */
43127
43128 /* Avoid using RegExp.prototype methods, as they're writable and
43129 * configurable and may have been changed.
43130 */
43131
43132 duk_dup_0(thr);
43133 duk_dup_1(thr); /* [ ... re_obj input ] */
43134 duk_regexp_match(thr); /* -> [ ... res_obj ] */
43135
43136 if (!duk_is_object(thr, -1)) {
43137 duk_push_int(thr, -1);
43138 return 1;
43139 }
43140
43141 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
43142 DUK_ASSERT(duk_is_number(thr, -1));
43143 return 1;
43144}
43145#endif /* DUK_USE_REGEXP_SUPPORT */
43146
43147#if defined(DUK_USE_REGEXP_SUPPORT)
43148DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) {
43149 duk_bool_t global;
43150 duk_int_t prev_last_index;
43151 duk_int_t this_index;
43152 duk_int_t arr_idx;
43153
43154 DUK_ASSERT_TOP(thr, 1);
43155 (void) duk_push_this_coercible_to_string(thr);
43156 duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/);
43157 global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
43158 DUK_ASSERT_TOP(thr, 2);
43159
43160 /* stack[0] = regexp
43161 * stack[1] = string
43162 */
43163
43164 if (!global) {
43165 duk_regexp_match(thr); /* -> [ res_obj ] */
43166 return 1; /* return 'res_obj' */
43167 }
43168
43169 /* Global case is more complex. */
43170
43171 /* [ regexp string ] */
43172
43173 duk_push_int(thr, 0);
43174 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
43175 duk_push_array(thr);
43176
43177 /* [ regexp string res_arr ] */
43178
43179 prev_last_index = 0;
43180 arr_idx = 0;
43181
43182 for (;;) {
43183 DUK_ASSERT_TOP(thr, 3);
43184
43185 duk_dup_0(thr);
43186 duk_dup_1(thr);
43187 duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
43188
43189 if (!duk_is_object(thr, -1)) {
43190 duk_pop(thr);
43191 break;
43192 }
43193
43194 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
43195 DUK_ASSERT(duk_is_number(thr, -1));
43196 this_index = duk_get_int(thr, -1);
43197 duk_pop(thr);
43198
43199 if (this_index == prev_last_index) {
43200 this_index++;
43201 duk_push_int(thr, this_index);
43202 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
43203 }
43204 prev_last_index = this_index;
43205
43206 duk_get_prop_index(thr, -1, 0); /* match string */
43207 duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx);
43208 arr_idx++;
43209 duk_pop(thr); /* res_obj */
43210 }
43211
43212 if (arr_idx == 0) {
43213 duk_push_null(thr);
43214 }
43215
43216 return 1; /* return 'res_arr' or 'null' */
43217}
43218#endif /* DUK_USE_REGEXP_SUPPORT */
43219
43220DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) {
43221 /* duk_concat() coerces arguments with ToString() in correct order */
43222 (void) duk_push_this_coercible_to_string(thr);
43223 duk_insert(thr, 0); /* this is relatively expensive */
43224 duk_concat(thr, duk_get_top(thr));
43225 return 1;
43226}
43227
43228DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) {
43229 DUK_ASSERT_TOP(thr, 0);
43230 (void) duk_push_this_coercible_to_string(thr);
43231 duk_trim(thr, 0);
43232 DUK_ASSERT_TOP(thr, 1);
43233 return 1;
43234}
43235
43236#if defined(DUK_USE_ES6)
43237DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
43238 duk_hstring *h_input;
43239 duk_size_t input_blen;
43240 duk_size_t result_len;
43241 duk_int_t count_signed;
43242 duk_uint_t count;
43243 const duk_uint8_t *src;
43244 duk_uint8_t *buf;
43245 duk_uint8_t *p;
43246 duk_double_t d;
43247#if !defined(DUK_USE_PREFER_SIZE)
43248 duk_size_t copy_size;
43249 duk_uint8_t *p_end;
43250#endif
43251
43252 DUK_ASSERT_TOP(thr, 1);
43253 h_input = duk_push_this_coercible_to_string(thr);
43254 DUK_ASSERT(h_input != NULL);
43255 input_blen = DUK_HSTRING_GET_BYTELEN(h_input);
43256
43257 /* Count is ToNumber() coerced; +Infinity must be always rejected
43258 * (even if input string is zero length), as well as negative values
43259 * and -Infinity. -Infinity doesn't require an explicit check
43260 * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected
43261 * as a negative value (regardless of input string length).
43262 */
43263 d = duk_to_number(thr, 0);
43264 if (duk_double_is_posinf(d)) {
43265 goto fail_range;
43266 }
43267 count_signed = duk_get_int(thr, 0);
43268 if (count_signed < 0) {
43269 goto fail_range;
43270 }
43271 count = (duk_uint_t) count_signed;
43272
43273 /* Overflow check for result length. */
43274 result_len = count * input_blen;
43275 if (count != 0 && result_len / count != input_blen) {
43276 goto fail_range;
43277 }
43278
43279 /* Temporary fixed buffer, later converted to string. */
43280 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
43281 DUK_ASSERT(buf != NULL);
43282 src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
43283 DUK_ASSERT(src != NULL);
43284
43285#if defined(DUK_USE_PREFER_SIZE)
43286 p = buf;
43287 while (count-- > 0) {
43288 duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero, but pointers are valid */
43289 p += input_blen;
43290 }
43291#else /* DUK_USE_PREFER_SIZE */
43292 /* Take advantage of already copied pieces to speed up the process
43293 * especially for small repeated strings.
43294 */
43295 p = buf;
43296 p_end = p + result_len;
43297 copy_size = input_blen;
43298 for (;;) {
43299 duk_size_t remain = (duk_size_t) (p_end - p);
43300 DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld",
43301 (long) remain, (long) copy_size, (long) input_blen,
43302 (long) result_len));
43303 if (remain <= copy_size) {
43304 /* If result_len is zero, this case is taken and does
43305 * a zero size copy (with valid pointers).
43306 */
43307 duk_memcpy((void *) p, (const void *) src, remain);
43308 break;
43309 } else {
43310 duk_memcpy((void *) p, (const void *) src, copy_size);
43311 p += copy_size;
43312 }
43313
43314 src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */
43315 copy_size = (duk_size_t) (p - buf);
43316 }
43317#endif /* DUK_USE_PREFER_SIZE */
43318
43319 /* XXX: It would be useful to be able to create a duk_hstring with
43320 * a certain byte size whose data area wasn't initialized and which
43321 * wasn't in the string table yet. This would allow a string to be
43322 * constructed directly without a buffer temporary and when it was
43323 * finished, it could be injected into the string table. Currently
43324 * this isn't possible because duk_hstrings are only tracked by the
43325 * intern table (they are not in heap_allocated).
43326 */
43327
43328 duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
43329 return 1;
43330
43331 fail_range:
43332 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
43333}
43334#endif /* DUK_USE_ES6 */
43335
43336DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) {
43337 duk_hstring *h1;
43338 duk_hstring *h2;
43339 duk_size_t h1_len, h2_len, prefix_len;
43340 duk_small_int_t ret = 0;
43341 duk_small_int_t rc;
43342
43343 /* The current implementation of localeCompare() is simply a codepoint
43344 * by codepoint comparison, implemented with a simple string compare
43345 * because UTF-8 should preserve codepoint ordering (assuming valid
43346 * shortest UTF-8 encoding).
43347 *
43348 * The specification requires that the return value must be related
43349 * to the sort order: e.g. negative means that 'this' comes before
43350 * 'that' in sort order. We assume an ascending sort order.
43351 */
43352
43353 /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
43354
43355 h1 = duk_push_this_coercible_to_string(thr);
43356 DUK_ASSERT(h1 != NULL);
43357
43358 h2 = duk_to_hstring(thr, 0);
43359 DUK_ASSERT(h2 != NULL);
43360
43361 h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
43362 h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
43363 prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
43364
43365 rc = (duk_small_int_t) duk_memcmp((const void *) DUK_HSTRING_GET_DATA(h1),
43366 (const void *) DUK_HSTRING_GET_DATA(h2),
43367 (size_t) prefix_len);
43368
43369 if (rc < 0) {
43370 ret = -1;
43371 goto done;
43372 } else if (rc > 0) {
43373 ret = 1;
43374 goto done;
43375 }
43376
43377 /* prefix matches, lengths matter now */
43378 if (h1_len > h2_len) {
43379 ret = 1;
43380 goto done;
43381 } else if (h1_len == h2_len) {
43382 DUK_ASSERT(ret == 0);
43383 goto done;
43384 }
43385 ret = -1;
43386 goto done;
43387
43388 done:
43389 duk_push_int(thr, (duk_int_t) ret);
43390 return 1;
43391}
43392
43393#if defined(DUK_USE_ES6)
43394DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) {
43395 duk_int_t magic;
43396 duk_hstring *h_target;
43397 duk_size_t blen_target;
43398 duk_hstring *h_search;
43399 duk_size_t blen_search;
43400 duk_int_t off;
43401 duk_bool_t result = 0;
43402 duk_size_t blen_left;
43403
43404 /* Because string byte lengths are in [0,DUK_INT_MAX] it's safe to
43405 * subtract two string lengths without overflow.
43406 */
43407 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
43408
43409 h_target = duk_push_this_coercible_to_string(thr);
43410 DUK_ASSERT(h_target != NULL);
43411
43412 h_search = duk__str_tostring_notregexp(thr, 0);
43413 DUK_ASSERT(h_search != NULL);
43414
43415 magic = duk_get_current_magic(thr);
43416
43417 /* Careful to avoid pointer overflows in the matching logic. */
43418
43419 blen_target = DUK_HSTRING_GET_BYTELEN(h_target);
43420 blen_search = DUK_HSTRING_GET_BYTELEN(h_search);
43421
43422#if 0
43423 /* If search string is longer than the target string, we can
43424 * never match. Could check explicitly, but should be handled
43425 * correctly below.
43426 */
43427 if (blen_search > blen_target) {
43428 goto finish;
43429 }
43430#endif
43431
43432 off = 0;
43433 if (duk_is_undefined(thr, 1)) {
43434 if (magic) {
43435 off = (duk_int_t) blen_target - (duk_int_t) blen_search;
43436 } else {
43437 DUK_ASSERT(off == 0);
43438 }
43439 } else {
43440 duk_int_t len;
43441 duk_int_t pos;
43442
43443 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
43444 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_target);
43445 pos = duk_to_int_clamped(thr, 1, 0, len);
43446 DUK_ASSERT(pos >= 0 && pos <= len);
43447
43448 off = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_target, (duk_uint_fast32_t) pos);
43449 if (magic) {
43450 off -= (duk_int_t) blen_search;
43451 }
43452 }
43453 if (off < 0 || off > (duk_int_t) blen_target) {
43454 goto finish;
43455 }
43456
43457 /* The main comparison can be done using a memcmp() rather than
43458 * doing codepoint comparisons: for CESU-8 strings there is a
43459 * canonical representation for every codepoint. But we do need
43460 * to deal with the char/byte offset translation to find the
43461 * comparison range.
43462 */
43463
43464 DUK_ASSERT(off >= 0);
43465 DUK_ASSERT((duk_size_t) off <= blen_target);
43466 blen_left = blen_target - (duk_size_t) off;
43467 if (blen_left >= blen_search) {
43468 const duk_uint8_t *p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_target) + off;
43469 const duk_uint8_t *p_search = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_search);
43470 if (duk_memcmp_unsafe((const void *) p_cmp_start, (const void *) p_search, (size_t) blen_search) == 0) {
43471 result = 1;
43472 }
43473 }
43474
43475 finish:
43476 duk_push_boolean(thr, result);
43477 return 1;
43478}
43479#endif /* DUK_USE_ES6 */
43480
43481#if defined(DUK_USE_ES6)
43482DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) {
43483 duk_hstring *h;
43484 duk_hstring *h_search;
43485 duk_int_t len;
43486 duk_int_t pos;
43487
43488 h = duk_push_this_coercible_to_string(thr);
43489 DUK_ASSERT(h != NULL);
43490
43491 h_search = duk__str_tostring_notregexp(thr, 0);
43492 DUK_ASSERT(h_search != NULL);
43493
43494 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
43495 pos = duk_to_int_clamped(thr, 1, 0, len);
43496 DUK_ASSERT(pos >= 0 && pos <= len);
43497
43498 pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/);
43499 duk_push_boolean(thr, pos >= 0);
43500 return 1;
43501}
43502#endif /* DUK_USE_ES6 */
43503#endif /* DUK_USE_STRING_BUILTIN */
43504#line 1 "duk_bi_symbol.c"
43505/*
43506 * Symbol built-in
43507 */
43508
43509/* #include duk_internal.h -> already included */
43510
43511#if defined(DUK_USE_SYMBOL_BUILTIN)
43512
43513/*
43514 * Constructor
43515 */
43516
43517DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
43518 const duk_uint8_t *desc;
43519 duk_size_t len;
43520 duk_uint8_t *buf;
43521 duk_uint8_t *p;
43522 duk_int_t magic;
43523
43524 magic = duk_get_current_magic(thr);
43525 if (duk_is_undefined(thr, 0) && (magic == 0)) {
43526 /* Symbol() accepts undefined and empty string, but they are
43527 * treated differently.
43528 */
43529 desc = NULL;
43530 len = 0;
43531 } else {
43532 /* Symbol.for() coerces undefined to 'undefined' */
43533 desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len);
43534 }
43535
43536 /* Maximum symbol data length:
43537 * +1 initial byte (0x80 or 0x81)
43538 * +len description
43539 * +1 0xff after description, before unique suffix
43540 * +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest
43541 * +1 0xff after unique suffix for symbols with undefined description
43542 */
43543 buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
43544 DUK_ASSERT(buf != NULL);
43545 p = buf + 1;
43546 DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
43547 duk_memcpy_unsafe((void *) p, (const void *) desc, len);
43548 p += len;
43549 if (magic == 0) {
43550 /* Symbol(): create unique symbol. Use two 32-bit values
43551 * to avoid dependency on 64-bit types and 64-bit integer
43552 * formatting (at least for now).
43553 */
43554 if (++thr->heap->sym_counter[0] == 0) {
43555 thr->heap->sym_counter[1]++;
43556 }
43557 p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx",
43558 (unsigned long) thr->heap->sym_counter[1],
43559 (unsigned long) thr->heap->sym_counter[0]);
43560 if (desc == NULL) {
43561 /* Special case for 'undefined' description, trailing
43562 * 0xff distinguishes from empty string description,
43563 * but needs minimal special case handling elsewhere.
43564 */
43565 *p++ = 0xff;
43566 }
43567 buf[0] = 0x81;
43568 } else {
43569 /* Symbol.for(): create a global symbol */
43570 buf[0] = 0x80;
43571 }
43572
43573 duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
43574 DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1)));
43575 return 1;
43576}
43577
43578DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) {
43579 duk_tval *tv;
43580 duk_hobject *h_obj;
43581 duk_hstring *h_str;
43582
43583 DUK_ASSERT(tv_arg != NULL);
43584
43585 /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */
43586 /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */
43587
43588 tv = tv_arg;
43589 if (DUK_TVAL_IS_OBJECT(tv)) {
43590 h_obj = DUK_TVAL_GET_OBJECT(tv);
43591 DUK_ASSERT(h_obj != NULL);
43592 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
43593 tv = duk_hobject_get_internal_value_tval_ptr(thr->heap, h_obj);
43594 if (tv == NULL) {
43595 return NULL;
43596 }
43597 } else {
43598 return NULL;
43599 }
43600 }
43601
43602 if (!DUK_TVAL_IS_STRING(tv)) {
43603 return NULL;
43604 }
43605 h_str = DUK_TVAL_GET_STRING(tv);
43606 DUK_ASSERT(h_str != NULL);
43607
43608 /* Here symbol is more expected than not. */
43609 if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) {
43610 return NULL;
43611 }
43612
43613 return h_str;
43614}
43615
43616DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) {
43617 duk_hstring *h_str;
43618
43619 h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
43620 if (h_str == NULL) {
43621 return DUK_RET_TYPE_ERROR;
43622 }
43623
43624 if (duk_get_current_magic(thr) == 0) {
43625 /* .toString() */
43626 duk_push_symbol_descriptive_string(thr, h_str);
43627 } else {
43628 /* .valueOf() */
43629 duk_push_hstring(thr, h_str);
43630 }
43631 return 1;
43632}
43633
43634DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) {
43635 duk_hstring *h;
43636 const duk_uint8_t *p;
43637
43638 /* Argument must be a symbol but not checked here. The initial byte
43639 * check will catch non-symbol strings.
43640 */
43641 h = duk_require_hstring(thr, 0);
43642 DUK_ASSERT(h != NULL);
43643
43644 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
43645 DUK_ASSERT(p != NULL);
43646
43647 /* Even for zero length strings there's at least one NUL byte so
43648 * we can safely check the initial byte.
43649 */
43650 if (p[0] == 0x80) {
43651 /* Global symbol, return its key (bytes just after the initial byte). */
43652 duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1));
43653 return 1;
43654 } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) {
43655 /* Local symbol or hidden symbol, return undefined. */
43656 return 0;
43657 }
43658
43659 /* Covers normal strings and unknown initial bytes. */
43660 return DUK_RET_TYPE_ERROR;
43661}
43662
43663DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) {
43664 duk_hstring *h_str;
43665
43666 h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
43667 if (h_str == NULL) {
43668 return DUK_RET_TYPE_ERROR;
43669 }
43670 duk_push_hstring(thr, h_str);
43671 return 1;
43672}
43673
43674#endif /* DUK_USE_SYMBOL_BUILTIN */
43675#line 1 "duk_bi_thread.c"
43676/*
43677 * Thread builtins
43678 */
43679
43680/* #include duk_internal.h -> already included */
43681
43682/*
43683 * Constructor
43684 */
43685
43686#if defined(DUK_USE_COROUTINE_SUPPORT)
43687DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
43688 duk_hthread *new_thr;
43689 duk_hobject *func;
43690
43691 /* Check that the argument is callable; this is not 100% because we
43692 * don't allow native functions to be a thread's initial function.
43693 * Resume will reject such functions in any case.
43694 */
43695 /* XXX: need a duk_require_func_promote_lfunc() */
43696 func = duk_require_hobject_promote_lfunc(thr, 0);
43697 DUK_ASSERT(func != NULL);
43698 duk_require_callable(thr, 0);
43699
43700 duk_push_thread(thr);
43701 new_thr = (duk_hthread *) duk_known_hobject(thr, -1);
43702 new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
43703
43704 /* push initial function call to new thread stack; this is
43705 * picked up by resume().
43706 */
43707 duk_push_hobject(new_thr, func);
43708
43709 return 1; /* return thread */
43710}
43711#endif
43712
43713/*
43714 * Resume a thread.
43715 *
43716 * The thread must be in resumable state, either (a) new thread which hasn't
43717 * yet started, or (b) a thread which has previously yielded. This method
43718 * must be called from an ECMAScript function.
43719 *
43720 * Args:
43721 * - thread
43722 * - value
43723 * - isError (defaults to false)
43724 *
43725 * Note: yield and resume handling is currently asymmetric.
43726 */
43727
43728#if defined(DUK_USE_COROUTINE_SUPPORT)
43729DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
43730 duk_hthread *thr = (duk_hthread *) ctx;
43731 duk_hthread *thr_resume;
43732 duk_hobject *caller_func;
43733 duk_small_uint_t is_error;
43734
43735 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
43736 (duk_tval *) duk_get_tval(thr, 0),
43737 (duk_tval *) duk_get_tval(thr, 1),
43738 (duk_tval *) duk_get_tval(thr, 2)));
43739
43740 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
43741 DUK_ASSERT(thr->heap->curr_thread == thr);
43742
43743 thr_resume = duk_require_hthread(thr, 0);
43744 DUK_ASSERT(duk_get_top(thr) == 3);
43745 is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
43746 DUK_ASSERT(duk_get_top(thr) == 2);
43747
43748 /* [ thread value ] */
43749
43750 /*
43751 * Thread state and calling context checks
43752 */
43753
43754 if (thr->callstack_top < 2) {
43755 DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
43756 goto state_error;
43757 }
43758 DUK_ASSERT(thr->callstack_curr != NULL);
43759 DUK_ASSERT(thr->callstack_curr->parent != NULL);
43760 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
43761 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
43762 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
43763
43764 caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
43765 if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
43766 DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code"));
43767 goto state_error;
43768 }
43769
43770 /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
43771 * like for yield.
43772 */
43773
43774 if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
43775 thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
43776 DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
43777 goto state_error;
43778 }
43779
43780 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
43781 thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
43782
43783 /* Further state-dependent pre-checks */
43784
43785 if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
43786 /* no pre-checks now, assume a previous yield() has left things in
43787 * tip-top shape (longjmp handler will assert for these).
43788 */
43789 } else {
43790 duk_hobject *h_fun;
43791
43792 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
43793
43794 /* The initial function must be an ECMAScript function (but
43795 * can be bound). We must make sure of that before we longjmp
43796 * because an error in the RESUME handler call processing will
43797 * not be handled very cleanly.
43798 */
43799 if ((thr_resume->callstack_top != 0) ||
43800 (thr_resume->valstack_top - thr_resume->valstack != 1)) {
43801 goto state_error;
43802 }
43803
43804 duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1));
43805 duk_resolve_nonbound_function(thr);
43806 h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */
43807 if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
43808 goto state_error;
43809 }
43810 duk_pop(thr);
43811 }
43812
43813#if 0
43814 /* This check would prevent a heap destruction time finalizer from
43815 * launching a coroutine, which would ensure that during finalization
43816 * 'thr' would always equal heap_thread. Normal runtime finalizers
43817 * run with ms_running == 0, i.e. outside mark-and-sweep. See GH-2030.
43818 */
43819 if (thr->heap->ms_running) {
43820 DUK_D(DUK_DPRINT("refuse Duktape.Thread.resume() when ms_running != 0"));
43821 goto state_error;
43822 }
43823#endif
43824
43825 /*
43826 * The error object has been augmented with a traceback and other
43827 * info from its creation point -- usually another thread. The
43828 * error handler is called here right before throwing, but it also
43829 * runs in the resumer's thread. It might be nice to get a traceback
43830 * from the resumee but this is not the case now.
43831 */
43832
43833#if defined(DUK_USE_AUGMENT_ERROR_THROW)
43834 if (is_error) {
43835 DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */
43836 duk_err_augment_error_throw(thr); /* in resumer's context */
43837 }
43838#endif
43839
43840#if defined(DUK_USE_DEBUG)
43841 if (is_error) {
43842 DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
43843 (duk_tval *) duk_get_tval(thr, 0),
43844 (duk_tval *) duk_get_tval(thr, 1)));
43845 } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
43846 DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
43847 (duk_tval *) duk_get_tval(thr, 0),
43848 (duk_tval *) duk_get_tval(thr, 1)));
43849 } else {
43850 DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
43851 (duk_tval *) duk_get_tval(thr, 0),
43852 (duk_tval *) duk_get_tval(thr, 1)));
43853 }
43854#endif
43855
43856 thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
43857
43858 /* lj value2: thread */
43859 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
43860 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
43861
43862 /* lj value1: value */
43863 DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
43864 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
43865 DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
43866
43867 thr->heap->lj.iserror = is_error;
43868
43869 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
43870 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
43871 DUK_UNREACHABLE();
43872 /* Never here, fall through to error (from compiler point of view). */
43873
43874 state_error:
43875 DUK_DCERROR_TYPE_INVALID_STATE(thr);
43876}
43877#endif
43878
43879/*
43880 * Yield the current thread.
43881 *
43882 * The thread must be in yieldable state: it must have a resumer, and there
43883 * must not be any yield-preventing calls (native calls and constructor calls,
43884 * currently) in the thread's call stack (otherwise a resume would not be
43885 * possible later). This method must be called from an ECMAScript function.
43886 *
43887 * Args:
43888 * - value
43889 * - isError (defaults to false)
43890 *
43891 * Note: yield and resume handling is currently asymmetric.
43892 */
43893
43894#if defined(DUK_USE_COROUTINE_SUPPORT)
43895DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
43896 duk_hobject *caller_func;
43897 duk_small_uint_t is_error;
43898
43899 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
43900 (duk_tval *) duk_get_tval(thr, 0),
43901 (duk_tval *) duk_get_tval(thr, 1)));
43902
43903 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
43904 DUK_ASSERT(thr->heap->curr_thread == thr);
43905
43906 DUK_ASSERT(duk_get_top(thr) == 2);
43907 is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
43908 DUK_ASSERT(duk_get_top(thr) == 1);
43909
43910 /* [ value ] */
43911
43912 /*
43913 * Thread state and calling context checks
43914 */
43915
43916 if (!thr->resumer) {
43917 DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
43918 goto state_error;
43919 }
43920 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
43921
43922 if (thr->callstack_top < 2) {
43923 DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
43924 goto state_error;
43925 }
43926 DUK_ASSERT(thr->callstack_curr != NULL);
43927 DUK_ASSERT(thr->callstack_curr->parent != NULL);
43928 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
43929 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
43930 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
43931
43932 caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
43933 if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
43934 DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code"));
43935 goto state_error;
43936 }
43937
43938 DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
43939 if (thr->callstack_preventcount != 1) {
43940 /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
43941 DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
43942 (long) thr->callstack_preventcount));
43943 goto state_error;
43944 }
43945
43946 /*
43947 * The error object has been augmented with a traceback and other
43948 * info from its creation point -- usually the current thread.
43949 * The error handler, however, is called right before throwing
43950 * and runs in the yielder's thread.
43951 */
43952
43953#if defined(DUK_USE_AUGMENT_ERROR_THROW)
43954 if (is_error) {
43955 DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */
43956 duk_err_augment_error_throw(thr); /* in yielder's context */
43957 }
43958#endif
43959
43960#if defined(DUK_USE_DEBUG)
43961 if (is_error) {
43962 DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
43963 (duk_tval *) duk_get_tval(thr, 0)));
43964 } else {
43965 DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
43966 (duk_tval *) duk_get_tval(thr, 0)));
43967 }
43968#endif
43969
43970 /*
43971 * Process yield
43972 *
43973 * After longjmp(), processing continues in bytecode executor longjmp
43974 * handler, which will e.g. update thr->resumer to NULL.
43975 */
43976
43977 thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
43978
43979 /* lj value1: value */
43980 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
43981 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
43982 DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
43983
43984 thr->heap->lj.iserror = is_error;
43985
43986 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
43987 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
43988 DUK_UNREACHABLE();
43989 /* Never here, fall through to error (from compiler point of view). */
43990
43991 state_error:
43992 DUK_DCERROR_TYPE_INVALID_STATE(thr);
43993}
43994#endif
43995
43996#if defined(DUK_USE_COROUTINE_SUPPORT)
43997DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) {
43998 duk_push_current_thread(thr);
43999 return 1;
44000}
44001#endif
44002#line 1 "duk_bi_thrower.c"
44003/*
44004 * Type error thrower, E5 Section 13.2.3.
44005 */
44006
44007/* #include duk_internal.h -> already included */
44008
44009DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) {
44010 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
44011}
44012#line 1 "duk_debug_fixedbuffer.c"
44013/*
44014 * Fixed buffer helper useful for debugging, requires no allocation
44015 * which is critical for debugging.
44016 */
44017
44018/* #include duk_internal.h -> already included */
44019
44020#if defined(DUK_USE_DEBUG)
44021
44022DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
44023 duk_size_t avail;
44024 duk_size_t copylen;
44025
44026 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
44027 if (length > avail) {
44028 copylen = avail;
44029 fb->truncated = 1;
44030 } else {
44031 copylen = length;
44032 }
44033 duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen);
44034 fb->offset += copylen;
44035}
44036
44037DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
44038 duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
44039}
44040
44041DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
44042 duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
44043}
44044
44045DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
44046 duk_size_t avail;
44047 va_list ap;
44048
44049 va_start(ap, fmt);
44050 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
44051 if (avail > 0) {
44052 duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
44053 if (res < 0) {
44054 /* error */
44055 } else if ((duk_size_t) res >= avail) {
44056 /* (maybe) truncated */
44057 fb->offset += avail;
44058 if ((duk_size_t) res > avail) {
44059 /* actual chars dropped (not just NUL term) */
44060 fb->truncated = 1;
44061 }
44062 } else {
44063 /* normal */
44064 fb->offset += (duk_size_t) res;
44065 }
44066 }
44067 va_end(ap);
44068}
44069
44070DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
44071 char buf[64+1];
44072 duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
44073 buf[sizeof(buf) - 1] = (char) 0;
44074 duk_fb_put_cstring(fb, buf);
44075}
44076
44077DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
44078 return (fb->offset >= fb->length);
44079}
44080
44081#endif /* DUK_USE_DEBUG */
44082#line 1 "duk_debug_vsnprintf.c"
44083/*
44084 * Custom formatter for debug printing, allowing Duktape specific data
44085 * structures (such as tagged values and heap objects) to be printed with
44086 * a nice format string. Because debug printing should not affect execution
44087 * state, formatting here must be independent of execution (see implications
44088 * below) and must not allocate memory.
44089 *
44090 * Custom format tags begin with a '%!' to safely distinguish them from
44091 * standard format tags. The following conversions are supported:
44092 *
44093 * %!T tagged value (duk_tval *)
44094 * %!O heap object (duk_heaphdr *)
44095 * %!I decoded bytecode instruction
44096 * %!X bytecode instruction opcode name (arg is long)
44097 * %!C catcher (duk_catcher *)
44098 * %!A activation (duk_activation *)
44099 *
44100 * Everything is serialized in a JSON-like manner. The default depth is one
44101 * level, internal prototype is not followed, and internal properties are not
44102 * serialized. The following modifiers change this behavior:
44103 *
44104 * @ print pointers
44105 * # print binary representations (where applicable)
44106 * d deep traversal of own properties (not prototype)
44107 * p follow prototype chain (useless without 'd')
44108 * i include internal properties (other than prototype)
44109 * x hexdump buffers
44110 * h heavy formatting
44111 *
44112 * For instance, the following serializes objects recursively, but does not
44113 * follow the prototype chain nor print internal properties: "%!dO".
44114 *
44115 * Notes:
44116 *
44117 * * Standard snprintf return value semantics seem to vary. This
44118 * implementation returns the number of bytes it actually wrote
44119 * (excluding the null terminator). If retval == buffer size,
44120 * output was truncated (except for corner cases).
44121 *
44122 * * Output format is intentionally different from ECMAScript
44123 * formatting requirements, as formatting here serves debugging
44124 * of internals.
44125 *
44126 * * Depth checking (and updating) is done in each type printer
44127 * separately, to allow them to call each other freely.
44128 *
44129 * * Some pathological structures might take ages to print (e.g.
44130 * self recursion with 100 properties pointing to the object
44131 * itself). To guard against these, each printer also checks
44132 * whether the output buffer is full; if so, early exit.
44133 *
44134 * * Reference loops are detected using a loop stack.
44135 */
44136
44137/* #include duk_internal.h -> already included */
44138
44139#if defined(DUK_USE_DEBUG)
44140
44141/* #include stdio.h -> already included */
44142/* #include stdarg.h -> already included */
44143#include <string.h>
44144
44145/* list of conversion specifiers that terminate a format tag;
44146 * this is unfortunately guesswork.
44147 */
44148#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm"
44149
44150/* maximum length of standard format tag that we support */
44151#define DUK__MAX_FORMAT_TAG_LENGTH 32
44152
44153/* heapobj recursion depth when deep printing is selected */
44154#define DUK__DEEP_DEPTH_LIMIT 8
44155
44156/* maximum recursion depth for loop detection stacks */
44157#define DUK__LOOP_STACK_DEPTH 256
44158
44159/* must match bytecode defines now; build autogenerate? */
44160DUK_LOCAL const char * const duk__bc_optab[256] = {
44161 "LDREG", "STREG", "JUMP", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF",
44162 "LDNULL", "LDTRUE", "LDFALSE", "GETVAR", "BNOT", "LNOT", "UNM", "UNP",
44163 "EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC",
44164 "SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC",
44165
44166 "GT_RR", "GT_CR", "GT_RC", "GT_CC", "GE_RR", "GE_CR", "GE_RC", "GE_CC",
44167 "LT_RR", "LT_CR", "LT_RC", "LT_CC", "LE_RR", "LE_CR", "LE_RC", "LE_CC",
44168 "IFTRUE_R", "IFTRUE_C", "IFFALSE_R", "IFFALSE_C", "ADD_RR", "ADD_CR", "ADD_RC", "ADD_CC",
44169 "SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC",
44170
44171 "DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC",
44172 "EXP_RR", "EXP_CR", "EXP_RC", "EXP_CC", "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC",
44173 "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC", "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC",
44174 "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC", "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC",
44175
44176 "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC", "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC",
44177 "IN_RR", "IN_CR", "IN_RC", "IN_CC", "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC",
44178 "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC", "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC",
44179 "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
44180
44181 "PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC",
44182 "POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC",
44183 "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC", "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC",
44184 "CLOSURE", "TYPEOF", "TYPEOFID", "PUTVAR", "DELVAR", "RETREG", "RETUNDEF", "RETCONST",
44185
44186 "RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH",
44187 "ENDFIN", "THROW", "INVLHS", "CSREG", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
44188 "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7",
44189 "CALL8", "CALL9", "CALL10", "CALL11", "CALL12", "CALL13", "CALL14", "CALL15",
44190
44191 "NEWOBJ", "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI",
44192 "SETALEN", "INITENUM", "NEXTENUM", "NEWTARGET", "DEBUGGER", "NOP", "INVALID", "UNUSED207",
44193 "GETPROPC_RR", "GETPROPC_CR", "GETPROPC_RC", "GETPROPC_CC", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
44194 "UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223",
44195
44196 "UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231",
44197 "UNUSED232", "UNUSED233", "UNUSED234", "UNUSED235", "UNUSED236", "UNUSED237", "UNUSED238", "UNUSED239",
44198 "UNUSED240", "UNUSED241", "UNUSED242", "UNUSED243", "UNUSED244", "UNUSED245", "UNUSED246", "UNUSED247",
44199 "UNUSED248", "UNUSED249", "UNUSED250", "UNUSED251", "UNUSED252", "UNUSED253", "UNUSED254", "UNUSED255"
44200};
44201
44202typedef struct duk__dprint_state duk__dprint_state;
44203struct duk__dprint_state {
44204 duk_fixedbuffer *fb;
44205
44206 /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
44207 * to not couple these two mechanisms unnecessarily.
44208 */
44209 duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
44210 duk_int_t loop_stack_index;
44211 duk_int_t loop_stack_limit;
44212
44213 duk_int_t depth;
44214 duk_int_t depth_limit;
44215
44216 duk_bool_t pointer;
44217 duk_bool_t heavy;
44218 duk_bool_t binary;
44219 duk_bool_t follow_proto;
44220 duk_bool_t internal;
44221 duk_bool_t hexdump;
44222};
44223
44224/* helpers */
44225DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
44226DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
44227DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
44228DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
44229DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
44230DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
44231DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
44232DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
44233
44234DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
44235 duk_fixedbuffer *fb = st->fb;
44236
44237 if (st->heavy) {
44238 duk_fb_sprintf(fb, "(%p)", (void *) h);
44239 }
44240
44241 if (!h) {
44242 return;
44243 }
44244
44245 if (st->binary) {
44246 duk_size_t i;
44247 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
44248 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
44249 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
44250 }
44251 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
44252 }
44253
44254#if defined(DUK_USE_REFERENCE_COUNTING) /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
44255 if (st->heavy) {
44256 duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
44257 "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
44258 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
44259 (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
44260 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
44261 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
44262 (long) DUK_HEAPHDR_GET_TYPE(h),
44263 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
44264 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
44265 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
44266 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
44267 }
44268#else
44269 if (st->heavy) {
44270 duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
44271 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
44272 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
44273 (long) DUK_HEAPHDR_GET_TYPE(h),
44274 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
44275 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
44276 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
44277 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
44278 }
44279#endif
44280}
44281
44282DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
44283 duk_fixedbuffer *fb = st->fb;
44284
44285 if (st->heavy) {
44286 duk_fb_sprintf(fb, "(%p)", (void *) h);
44287 }
44288
44289 if (!h) {
44290 return;
44291 }
44292
44293 if (st->binary) {
44294 duk_size_t i;
44295 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
44296 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
44297 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
44298 }
44299 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
44300 }
44301
44302#if defined(DUK_USE_REFERENCE_COUNTING)
44303 if (st->heavy) {
44304 duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
44305 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
44306 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
44307 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
44308 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
44309 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
44310 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
44311 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
44312 }
44313#else
44314 if (st->heavy) {
44315 duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
44316 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
44317 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
44318 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
44319 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
44320 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
44321 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
44322 }
44323#endif
44324}
44325
44326DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
44327 duk_fixedbuffer *fb = st->fb;
44328 const duk_uint8_t *p;
44329 const duk_uint8_t *p_end;
44330
44331 /* terminal type: no depth check */
44332
44333 if (duk_fb_is_full(fb)) {
44334 return;
44335 }
44336
44337 duk__print_shared_heaphdr_string(st, &h->hdr);
44338
44339 if (!h) {
44340 duk_fb_put_cstring(fb, "NULL");
44341 return;
44342 }
44343
44344 p = DUK_HSTRING_GET_DATA(h);
44345 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
44346
44347 if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
44348 /* If property key begins with underscore, encode it with
44349 * forced quotes (e.g. "_Foo") to distinguish it from encoded
44350 * internal properties (e.g. \x82Bar -> _Bar).
44351 */
44352 quotes = 1;
44353 }
44354
44355 if (quotes) {
44356 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
44357 }
44358 while (p < p_end) {
44359 duk_uint8_t ch = *p++;
44360
44361 /* two special escapes: '\' and '"', other printables as is */
44362 if (ch == '\\') {
44363 duk_fb_sprintf(fb, "\\\\");
44364 } else if (ch == '"') {
44365 duk_fb_sprintf(fb, "\\\"");
44366 } else if (ch >= 0x20 && ch <= 0x7e) {
44367 duk_fb_put_byte(fb, ch);
44368 } else if (ch == 0x82 && !quotes) {
44369 /* encode \x82Bar as _Bar if no quotes are
44370 * applied, this is for readable internal keys.
44371 */
44372 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
44373 } else {
44374 duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
44375 }
44376 }
44377 if (quotes) {
44378 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
44379 }
44380#if defined(DUK_USE_REFERENCE_COUNTING)
44381 /* XXX: limit to quoted strings only, to save keys from being cluttered? */
44382 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
44383#endif
44384}
44385
44386#define DUK__COMMA() do { \
44387 if (first) { \
44388 first = 0; \
44389 } else { \
44390 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
44391 } \
44392 } while (0)
44393
44394DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
44395 duk_fixedbuffer *fb = st->fb;
44396 duk_uint_fast32_t i;
44397 duk_tval *tv;
44398 duk_hstring *key;
44399 duk_bool_t first = 1;
44400 const char *brace1 = "{";
44401 const char *brace2 = "}";
44402 duk_bool_t pushed_loopstack = 0;
44403
44404 if (duk_fb_is_full(fb)) {
44405 return;
44406 }
44407
44408 duk__print_shared_heaphdr(st, &h->hdr);
44409
44410 if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
44411 brace1 = "[";
44412 brace2 = "]";
44413 }
44414
44415 if (!h) {
44416 duk_fb_put_cstring(fb, "NULL");
44417 goto finished;
44418 }
44419
44420 if (st->depth >= st->depth_limit) {
44421 const char *subtype = "generic";
44422
44423 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
44424 subtype = "compfunc";
44425 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
44426 subtype = "natfunc";
44427 } else if (DUK_HOBJECT_IS_THREAD(h)) {
44428 subtype = "thread";
44429 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
44430 subtype = "bufobj";
44431 } else if (DUK_HOBJECT_IS_ARRAY(h)) {
44432 subtype = "array";
44433 }
44434 duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2);
44435 return;
44436 }
44437
44438 for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
44439 if (st->loop_stack[i] == h) {
44440 duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
44441 return;
44442 }
44443 }
44444
44445 /* after this, return paths should 'goto finished' for decrement */
44446 st->depth++;
44447
44448 if (st->loop_stack_index >= st->loop_stack_limit) {
44449 duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
44450 goto finished;
44451 }
44452 st->loop_stack[st->loop_stack_index++] = h;
44453 pushed_loopstack = 1;
44454
44455 /*
44456 * Notation: double underscore used for internal properties which are not
44457 * stored in the property allocation (e.g. '__valstack').
44458 */
44459
44460 duk_fb_put_cstring(fb, brace1);
44461
44462 if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
44463 duk_uint32_t a_limit;
44464
44465 a_limit = DUK_HOBJECT_GET_ASIZE(h);
44466 if (st->internal) {
44467 /* dump all allocated entries, unused entries print as 'unused',
44468 * note that these may extend beyond current 'length' and look
44469 * a bit funny.
44470 */
44471 } else {
44472 /* leave out trailing 'unused' elements */
44473 while (a_limit > 0) {
44474 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
44475 if (!DUK_TVAL_IS_UNUSED(tv)) {
44476 break;
44477 }
44478 a_limit--;
44479 }
44480 }
44481
44482 for (i = 0; i < a_limit; i++) {
44483 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
44484 DUK__COMMA();
44485 duk__print_tval(st, tv);
44486 }
44487 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
44488 key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
44489 if (!key) {
44490 continue;
44491 }
44492 if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) {
44493 continue;
44494 }
44495 DUK__COMMA();
44496 duk__print_hstring(st, key, 0);
44497 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
44498 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
44499 duk_fb_sprintf(fb, "[get:%p,set:%p]",
44500 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
44501 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
44502 } else {
44503 tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
44504 duk__print_tval(st, tv);
44505 }
44506 if (st->heavy) {
44507 duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
44508 }
44509 }
44510 }
44511 if (st->internal) {
44512 if (DUK_HOBJECT_IS_ARRAY(h)) {
44513 DUK__COMMA(); duk_fb_sprintf(fb, "__array:true");
44514 }
44515 if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
44516 DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
44517 }
44518 if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
44519 DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
44520 }
44521 if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
44522 DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true");
44523 }
44524 if (DUK_HOBJECT_HAS_COMPFUNC(h)) {
44525 DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true");
44526 }
44527 if (DUK_HOBJECT_HAS_NATFUNC(h)) {
44528 DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true");
44529 }
44530 if (DUK_HOBJECT_HAS_BUFOBJ(h)) {
44531 DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true");
44532 }
44533 if (DUK_HOBJECT_IS_THREAD(h)) {
44534 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
44535 }
44536 if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
44537 DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
44538 }
44539 if (DUK_HOBJECT_HAS_STRICT(h)) {
44540 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
44541 }
44542 if (DUK_HOBJECT_HAS_NOTAIL(h)) {
44543 DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true");
44544 }
44545 if (DUK_HOBJECT_HAS_NEWENV(h)) {
44546 DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
44547 }
44548 if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
44549 DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
44550 }
44551 if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
44552 DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
44553 }
44554 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
44555 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
44556 }
44557 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
44558 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
44559 }
44560 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
44561 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
44562 }
44563 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
44564 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true");
44565 }
44566 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
44567 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
44568 }
44569 }
44570
44571 if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) {
44572 duk_harray *a = (duk_harray *) h;
44573 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length);
44574 DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable);
44575 } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) {
44576 duk_hcompfunc *f = (duk_hcompfunc *) h;
44577 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
44578 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
44579 DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f));
44580 DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f));
44581 DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
44582 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
44583#if defined(DUK_USE_DEBUGGER_SUPPORT)
44584 DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
44585 DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
44586#endif
44587 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
44588 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
44589 } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) {
44590 duk_hnatfunc *f = (duk_hnatfunc *) h;
44591 DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
44592 duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
44593 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
44594 DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
44595 } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) {
44596 duk_hdecenv *e = (duk_hdecenv *) h;
44597 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread);
44598 DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap);
44599 DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld", (long) e->regbase_byteoff);
44600 } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) {
44601 duk_hobjenv *e = (duk_hobjenv *) h;
44602 DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target);
44603 DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this);
44604#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
44605 } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) {
44606 duk_hbufobj *b = (duk_hbufobj *) h;
44607 DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
44608 duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
44609 DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:");
44610 duk__print_hobject(st, (duk_hobject *) b->buf_prop);
44611 DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
44612 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
44613 DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
44614 DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
44615#endif
44616 } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) {
44617 duk_hproxy *p = (duk_hproxy *) h;
44618 DUK__COMMA(); duk_fb_sprintf(fb, "__target:");
44619 duk__print_hobject(st, p->target);
44620 DUK__COMMA(); duk_fb_sprintf(fb, "__handler:");
44621 duk__print_hobject(st, p->handler);
44622 } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
44623 duk_hthread *t = (duk_hthread *) h;
44624 DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p", (void *) t->ptr_curr_pc);
44625 DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p", (void *) t->heap);
44626 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
44627 DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
44628 DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
44629 DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
44630 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
44631 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
44632 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld", (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack));
44633 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
44634 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
44635 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p", (void *) t->callstack_curr);
44636 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld", (long) t->callstack_top);
44637 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld", (long) t->callstack_preventcount);
44638 DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
44639 DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p", (void *) t->compile_ctx);
44640#if defined(DUK_USE_INTERRUPT_COUNTER)
44641 DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld", (long) t->interrupt_counter);
44642 DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld", (long) t->interrupt_init);
44643#endif
44644
44645 /* XXX: print built-ins array? */
44646
44647 }
44648#if defined(DUK_USE_REFERENCE_COUNTING)
44649 if (st->internal) {
44650 DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
44651 }
44652#endif
44653 if (st->internal) {
44654 DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
44655 }
44656
44657 DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */
44658
44659 /* prototype should be last, for readability */
44660 if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
44661 if (st->follow_proto) {
44662 DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
44663 } else {
44664 DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
44665 }
44666 }
44667
44668 duk_fb_put_cstring(fb, brace2);
44669
44670#if defined(DUK_USE_HOBJECT_HASH_PART)
44671 if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
44672 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
44673 for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
44674 duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
44675 if (i > 0) {
44676 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
44677 }
44678 if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
44679 duk_fb_sprintf(fb, "u");
44680 } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
44681 duk_fb_sprintf(fb, "d");
44682 } else {
44683 duk_fb_sprintf(fb, "%ld", (long) h_idx);
44684 }
44685 }
44686 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
44687 }
44688#endif
44689
44690 finished:
44691 st->depth--;
44692 if (pushed_loopstack) {
44693 st->loop_stack_index--;
44694 st->loop_stack[st->loop_stack_index] = NULL;
44695 }
44696}
44697
44698DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
44699 duk_fixedbuffer *fb = st->fb;
44700 duk_size_t i, n;
44701 duk_uint8_t *p;
44702
44703 if (duk_fb_is_full(fb)) {
44704 return;
44705 }
44706
44707 /* terminal type: no depth check */
44708
44709 if (!h) {
44710 duk_fb_put_cstring(fb, "NULL");
44711 return;
44712 }
44713
44714 if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
44715 if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
44716 duk_hbuffer_external *g = (duk_hbuffer_external *) h;
44717 duk_fb_sprintf(fb, "buffer:external:%p:%ld",
44718 (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
44719 (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
44720 } else {
44721 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
44722 duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
44723 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
44724 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
44725 }
44726 } else {
44727 duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
44728 }
44729
44730#if defined(DUK_USE_REFERENCE_COUNTING)
44731 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
44732#endif
44733
44734 if (st->hexdump) {
44735 duk_fb_sprintf(fb, "=[");
44736 n = DUK_HBUFFER_GET_SIZE(h);
44737 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
44738 for (i = 0; i < n; i++) {
44739 duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
44740 }
44741 duk_fb_sprintf(fb, "]");
44742 }
44743}
44744
44745DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
44746 duk_fixedbuffer *fb = st->fb;
44747
44748 if (duk_fb_is_full(fb)) {
44749 return;
44750 }
44751
44752 if (!h) {
44753 duk_fb_put_cstring(fb, "NULL");
44754 return;
44755 }
44756
44757 switch (DUK_HEAPHDR_GET_TYPE(h)) {
44758 case DUK_HTYPE_STRING:
44759 duk__print_hstring(st, (duk_hstring *) h, 1);
44760 break;
44761 case DUK_HTYPE_OBJECT:
44762 duk__print_hobject(st, (duk_hobject *) h);
44763 break;
44764 case DUK_HTYPE_BUFFER:
44765 duk__print_hbuffer(st, (duk_hbuffer *) h);
44766 break;
44767 default:
44768 duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
44769 break;
44770 }
44771}
44772
44773DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
44774 duk_fixedbuffer *fb = st->fb;
44775
44776 if (duk_fb_is_full(fb)) {
44777 return;
44778 }
44779
44780 /* depth check is done when printing an actual type */
44781
44782 if (st->heavy) {
44783 duk_fb_sprintf(fb, "(%p)", (void *) tv);
44784 }
44785
44786 if (!tv) {
44787 duk_fb_put_cstring(fb, "NULL");
44788 return;
44789 }
44790
44791 if (st->binary) {
44792 duk_size_t i;
44793 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
44794 for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
44795 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
44796 }
44797 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
44798 }
44799
44800 if (st->heavy) {
44801 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
44802 }
44803 switch (DUK_TVAL_GET_TAG(tv)) {
44804 case DUK_TAG_UNDEFINED: {
44805 duk_fb_put_cstring(fb, "undefined");
44806 break;
44807 }
44808 case DUK_TAG_UNUSED: {
44809 duk_fb_put_cstring(fb, "unused");
44810 break;
44811 }
44812 case DUK_TAG_NULL: {
44813 duk_fb_put_cstring(fb, "null");
44814 break;
44815 }
44816 case DUK_TAG_BOOLEAN: {
44817 duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
44818 break;
44819 }
44820 case DUK_TAG_STRING: {
44821 /* Note: string is a terminal heap object, so no depth check here */
44822 duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
44823 break;
44824 }
44825 case DUK_TAG_OBJECT: {
44826 duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
44827 break;
44828 }
44829 case DUK_TAG_BUFFER: {
44830 duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
44831 break;
44832 }
44833 case DUK_TAG_POINTER: {
44834 duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
44835 break;
44836 }
44837 case DUK_TAG_LIGHTFUNC: {
44838 duk_c_function func;
44839 duk_small_uint_t lf_flags;
44840
44841 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
44842 duk_fb_sprintf(fb, "lightfunc:");
44843 duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
44844 duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
44845 break;
44846 }
44847#if defined(DUK_USE_FASTINT)
44848 case DUK_TAG_FASTINT:
44849 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
44850 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
44851 duk_fb_sprintf(fb, "%.18g_F", (double) DUK_TVAL_GET_NUMBER(tv));
44852 break;
44853#endif
44854 default: {
44855 /* IEEE double is approximately 16 decimal digits; print a couple extra */
44856 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
44857 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
44858 duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
44859 break;
44860 }
44861 }
44862 if (st->heavy) {
44863 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
44864 }
44865}
44866
44867DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
44868 duk_fixedbuffer *fb = st->fb;
44869 duk_small_int_t op;
44870 const char *op_name;
44871
44872 op = (duk_small_int_t) DUK_DEC_OP(ins);
44873 op_name = duk__bc_optab[op];
44874
44875 /* XXX: option to fix opcode length so it lines up nicely */
44876
44877 if (op == DUK_OP_JUMP) {
44878 duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS); /* from next pc */
44879 duk_int_t diff2 = diff1 + 1; /* from curr pc */
44880
44881 duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
44882 (const char *) op_name, (long) diff1,
44883 (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */
44884 (long) (diff2 >= 0 ? diff2 : -diff2));
44885 } else {
44886 duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
44887 (const char *) op_name, (long) DUK_DEC_A(ins),
44888 (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
44889 }
44890}
44891
44892DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
44893 duk_fixedbuffer *fb = st->fb;
44894
44895 if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
44896 duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
44897 } else {
44898 duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
44899 }
44900}
44901
44902DUK_LOCAL void duk__print_catcher(duk__dprint_state *st, duk_catcher *cat) {
44903 duk_fixedbuffer *fb = st->fb;
44904
44905 if (duk_fb_is_full(fb)) {
44906 return;
44907 }
44908
44909 if (!cat) {
44910 duk_fb_put_cstring(fb, "NULL");
44911 return;
44912 }
44913
44914 duk_fb_sprintf(fb, "[catcher ptr=%p parent=%p varname=%p pc_base=%p, idx_base=%ld, flags=0x%08lx]",
44915 (void *) cat,
44916 (void *) cat->parent, (void *) cat->h_varname, (void *) cat->pc_base,
44917 (long) cat->idx_base, (unsigned long) cat->flags);
44918}
44919
44920
44921DUK_LOCAL void duk__print_activation(duk__dprint_state *st, duk_activation *act) {
44922 duk_fixedbuffer *fb = st->fb;
44923
44924 if (duk_fb_is_full(fb)) {
44925 return;
44926 }
44927
44928 if (!act) {
44929 duk_fb_put_cstring(fb, "NULL");
44930 return;
44931 }
44932
44933 /* prev_caller: conditional, omitted on purpose, it's rarely used. */
44934 /* prev_line: conditional, omitted on purpose (but would be nice). */
44935 duk_fb_sprintf(fb, "[activation ptr=%p tv_func=<omit> func=%p parent=%p var_env=%p lex_env=%p cat=%p curr_pc=%p bottom_byteoff=%ld retval_byteoff=%ld reserve_byteoff=%ld flags=%ld]",
44936 (void *) act,
44937 (void *) act->func, (void *) act->parent, (void *) act->var_env,
44938 (void *) act->lex_env, (void *) act->cat, (void *) act->curr_pc,
44939 (long) act->bottom_byteoff, (long) act->retval_byteoff, (long) act->reserve_byteoff,
44940 (long) act->flags);
44941}
44942
44943DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
44944 duk_fixedbuffer fb;
44945 const char *p = format;
44946 const char *p_end = p + DUK_STRLEN(format);
44947 duk_int_t retval;
44948
44949 duk_memzero(&fb, sizeof(fb));
44950 fb.buffer = (duk_uint8_t *) str;
44951 fb.length = size;
44952 fb.offset = 0;
44953 fb.truncated = 0;
44954
44955 while (p < p_end) {
44956 char ch = *p++;
44957 const char *p_begfmt = NULL;
44958 duk_bool_t got_exclamation = 0;
44959 duk_bool_t got_long = 0; /* %lf, %ld etc */
44960 duk__dprint_state st;
44961
44962 if (ch != DUK_ASC_PERCENT) {
44963 duk_fb_put_byte(&fb, (duk_uint8_t) ch);
44964 continue;
44965 }
44966
44967 /*
44968 * Format tag parsing. Since we don't understand all the
44969 * possible format tags allowed, we just scan for a terminating
44970 * specifier and keep track of relevant modifiers that we do
44971 * understand. See man 3 printf.
44972 */
44973
44974 duk_memzero(&st, sizeof(st));
44975 st.fb = &fb;
44976 st.depth = 0;
44977 st.depth_limit = 1;
44978 st.loop_stack_index = 0;
44979 st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
44980
44981 p_begfmt = p - 1;
44982 while (p < p_end) {
44983 ch = *p++;
44984
44985 if (ch == DUK_ASC_STAR) {
44986 /* unsupported: would consume multiple args */
44987 goto format_error;
44988 } else if (ch == DUK_ASC_PERCENT) {
44989 duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
44990 break;
44991 } else if (ch == DUK_ASC_EXCLAMATION) {
44992 got_exclamation = 1;
44993 } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
44994 got_long = 1;
44995 } else if (got_exclamation && ch == DUK_ASC_LC_D) {
44996 st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
44997 } else if (got_exclamation && ch == DUK_ASC_LC_P) {
44998 st.follow_proto = 1;
44999 } else if (got_exclamation && ch == DUK_ASC_LC_I) {
45000 st.internal = 1;
45001 } else if (got_exclamation && ch == DUK_ASC_LC_X) {
45002 st.hexdump = 1;
45003 } else if (got_exclamation && ch == DUK_ASC_LC_H) {
45004 st.heavy = 1;
45005 } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
45006 st.pointer = 1;
45007 } else if (got_exclamation && ch == DUK_ASC_HASH) {
45008 st.binary = 1;
45009 } else if (got_exclamation && ch == DUK_ASC_UC_T) {
45010 duk_tval *t = va_arg(ap, duk_tval *);
45011 if (st.pointer && !st.heavy) {
45012 duk_fb_sprintf(&fb, "(%p)", (void *) t);
45013 }
45014 duk__print_tval(&st, t);
45015 break;
45016 } else if (got_exclamation && ch == DUK_ASC_UC_O) {
45017 duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
45018 if (st.pointer && !st.heavy) {
45019 duk_fb_sprintf(&fb, "(%p)", (void *) t);
45020 }
45021 duk__print_heaphdr(&st, t);
45022 break;
45023 } else if (got_exclamation && ch == DUK_ASC_UC_I) {
45024 duk_instr_t t = va_arg(ap, duk_instr_t);
45025 duk__print_instr(&st, t);
45026 break;
45027 } else if (got_exclamation && ch == DUK_ASC_UC_X) {
45028 long t = va_arg(ap, long);
45029 duk__print_opcode(&st, (duk_small_int_t) t);
45030 break;
45031 } else if (got_exclamation && ch == DUK_ASC_UC_C) {
45032 duk_catcher *t = va_arg(ap, duk_catcher *);
45033 duk__print_catcher(&st, t);
45034 break;
45035 } else if (got_exclamation && ch == DUK_ASC_UC_A) {
45036 duk_activation *t = va_arg(ap, duk_activation *);
45037 duk__print_activation(&st, t);
45038 break;
45039 } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
45040 char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
45041 duk_size_t fmtlen;
45042
45043 DUK_ASSERT(p >= p_begfmt);
45044 fmtlen = (duk_size_t) (p - p_begfmt);
45045 if (fmtlen >= sizeof(fmtbuf)) {
45046 /* format is too large, abort */
45047 goto format_error;
45048 }
45049 duk_memzero(fmtbuf, sizeof(fmtbuf));
45050 duk_memcpy(fmtbuf, p_begfmt, fmtlen);
45051
45052 /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
45053 * depends on type though.
45054 */
45055
45056 if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
45057 /* %f and %lf both consume a 'long' */
45058 double arg = va_arg(ap, double);
45059 duk_fb_sprintf(&fb, fmtbuf, arg);
45060 } else if (ch == DUK_ASC_LC_D && got_long) {
45061 /* %ld */
45062 long arg = va_arg(ap, long);
45063 duk_fb_sprintf(&fb, fmtbuf, arg);
45064 } else if (ch == DUK_ASC_LC_D) {
45065 /* %d; only 16 bits are guaranteed */
45066 int arg = va_arg(ap, int);
45067 duk_fb_sprintf(&fb, fmtbuf, arg);
45068 } else if (ch == DUK_ASC_LC_U && got_long) {
45069 /* %lu */
45070 unsigned long arg = va_arg(ap, unsigned long);
45071 duk_fb_sprintf(&fb, fmtbuf, arg);
45072 } else if (ch == DUK_ASC_LC_U) {
45073 /* %u; only 16 bits are guaranteed */
45074 unsigned int arg = va_arg(ap, unsigned int);
45075 duk_fb_sprintf(&fb, fmtbuf, arg);
45076 } else if (ch == DUK_ASC_LC_X && got_long) {
45077 /* %lx */
45078 unsigned long arg = va_arg(ap, unsigned long);
45079 duk_fb_sprintf(&fb, fmtbuf, arg);
45080 } else if (ch == DUK_ASC_LC_X) {
45081 /* %x; only 16 bits are guaranteed */
45082 unsigned int arg = va_arg(ap, unsigned int);
45083 duk_fb_sprintf(&fb, fmtbuf, arg);
45084 } else if (ch == DUK_ASC_LC_S) {
45085 /* %s */
45086 const char *arg = va_arg(ap, const char *);
45087 if (arg == NULL) {
45088 /* '%s' and NULL is not portable, so special case
45089 * it for debug printing.
45090 */
45091 duk_fb_sprintf(&fb, "NULL");
45092 } else {
45093 duk_fb_sprintf(&fb, fmtbuf, arg);
45094 }
45095 } else if (ch == DUK_ASC_LC_P) {
45096 /* %p */
45097 void *arg = va_arg(ap, void *);
45098 if (arg == NULL) {
45099 /* '%p' and NULL is portable, but special case it
45100 * anyway to get a standard NULL marker in logs.
45101 */
45102 duk_fb_sprintf(&fb, "NULL");
45103 } else {
45104 duk_fb_sprintf(&fb, fmtbuf, arg);
45105 }
45106 } else if (ch == DUK_ASC_LC_C) {
45107 /* '%c', passed concretely as int */
45108 int arg = va_arg(ap, int);
45109 duk_fb_sprintf(&fb, fmtbuf, arg);
45110 } else {
45111 /* Should not happen. */
45112 duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
45113 }
45114 break;
45115 } else {
45116 /* ignore */
45117 }
45118 }
45119 }
45120 goto done;
45121
45122 format_error:
45123 duk_fb_put_cstring(&fb, "FMTERR");
45124 /* fall through */
45125
45126 done:
45127 retval = (duk_int_t) fb.offset;
45128 duk_fb_put_byte(&fb, (duk_uint8_t) 0);
45129
45130 /* return total chars written excluding terminator */
45131 return retval;
45132}
45133
45134#if 0 /*unused*/
45135DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
45136 duk_int_t retval;
45137 va_list ap;
45138 va_start(ap, format);
45139 retval = duk_debug_vsnprintf(str, size, format, ap);
45140 va_end(ap);
45141 return retval;
45142}
45143#endif
45144
45145/* Formatting function pointers is tricky: there is no standard pointer for
45146 * function pointers and the size of a function pointer may depend on the
45147 * specific pointer type. This helper formats a function pointer based on
45148 * its memory layout to get something useful on most platforms.
45149 */
45150DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
45151 duk_size_t i;
45152 duk_uint8_t *p = (duk_uint8_t *) buf;
45153 duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
45154
45155 DUK_ASSERT(buf != NULL);
45156 duk_memzero(buf, buf_size);
45157
45158 for (i = 0; i < fptr_size; i++) {
45159 duk_int_t left = (duk_int_t) (p_end - p);
45160 duk_uint8_t ch;
45161 if (left <= 0) {
45162 break;
45163 }
45164
45165 /* Quite approximate but should be useful for little and big endian. */
45166#if defined(DUK_USE_INTEGER_BE)
45167 ch = fptr[i];
45168#else
45169 ch = fptr[fptr_size - 1 - i];
45170#endif
45171 p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx", (unsigned long) ch);
45172 }
45173}
45174
45175#endif /* DUK_USE_DEBUG */
45176
45177/* automatic undefs */
45178#undef DUK__ALLOWED_STANDARD_SPECIFIERS
45179#undef DUK__COMMA
45180#undef DUK__DEEP_DEPTH_LIMIT
45181#undef DUK__LOOP_STACK_DEPTH
45182#undef DUK__MAX_FORMAT_TAG_LENGTH
45183#line 1 "duk_debugger.c"
45184/*
45185 * Duktape debugger
45186 */
45187
45188/* #include duk_internal.h -> already included */
45189
45190#if defined(DUK_USE_DEBUGGER_SUPPORT)
45191
45192/*
45193 * Assert helpers
45194 */
45195
45196#if defined(DUK_USE_ASSERTIONS)
45197#define DUK__DBG_TPORT_ENTER() do { \
45198 DUK_ASSERT(heap->dbg_calling_transport == 0); \
45199 heap->dbg_calling_transport = 1; \
45200 } while (0)
45201#define DUK__DBG_TPORT_EXIT() do { \
45202 DUK_ASSERT(heap->dbg_calling_transport == 1); \
45203 heap->dbg_calling_transport = 0; \
45204 } while (0)
45205#else
45206#define DUK__DBG_TPORT_ENTER() do {} while (0)
45207#define DUK__DBG_TPORT_EXIT() do {} while (0)
45208#endif
45209
45210/*
45211 * Helper structs
45212 */
45213
45214typedef union {
45215 void *p;
45216 duk_uint_t b[1];
45217 /* Use b[] to access the size of the union, which is strictly not
45218 * correct. Can't use fixed size unless there's feature detection
45219 * for pointer byte size.
45220 */
45221} duk__ptr_union;
45222
45223/*
45224 * Detach handling
45225 */
45226
45227#define DUK__SET_CONN_BROKEN(thr,reason) do { \
45228 /* For now shared handler is fine. */ \
45229 duk__debug_do_detach1((thr)->heap, (reason)); \
45230 } while (0)
45231
45232DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
45233 /* Can be called multiple times with no harm. Mark the transport
45234 * bad (dbg_read_cb == NULL) and clear state except for the detached
45235 * callback and the udata field. The detached callback is delayed
45236 * to the message loop so that it can be called between messages;
45237 * this avoids corner cases related to immediate debugger reattach
45238 * inside the detached callback.
45239 */
45240
45241 if (heap->dbg_detaching) {
45242 DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
45243 return;
45244 }
45245
45246 DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
45247
45248 heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
45249
45250 if (heap->dbg_write_cb != NULL) {
45251 duk_hthread *thr;
45252
45253 thr = heap->heap_thread;
45254 DUK_ASSERT(thr != NULL);
45255
45256 duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
45257 duk_debug_write_int(thr, reason);
45258 duk_debug_write_eom(thr);
45259 }
45260
45261 heap->dbg_read_cb = NULL;
45262 heap->dbg_write_cb = NULL;
45263 heap->dbg_peek_cb = NULL;
45264 heap->dbg_read_flush_cb = NULL;
45265 heap->dbg_write_flush_cb = NULL;
45266 heap->dbg_request_cb = NULL;
45267 /* heap->dbg_detached_cb: keep */
45268 /* heap->dbg_udata: keep */
45269 /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
45270 heap->dbg_state_dirty = 0;
45271 heap->dbg_force_restart = 0;
45272 heap->dbg_pause_flags = 0;
45273 heap->dbg_pause_act = NULL;
45274 heap->dbg_pause_startline = 0;
45275 heap->dbg_have_next_byte = 0;
45276 duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */
45277 heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */
45278
45279 /* Ensure there are no stale active breakpoint pointers.
45280 * Breakpoint list is currently kept - we could empty it
45281 * here but we'd need to handle refcounts correctly, and
45282 * we'd need a 'thr' reference for that.
45283 *
45284 * XXX: clear breakpoint on either attach or detach?
45285 */
45286 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
45287}
45288
45289DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
45290 duk_debug_detached_function detached_cb;
45291 void *detached_udata;
45292 duk_hthread *thr;
45293
45294 thr = heap->heap_thread;
45295 if (thr == NULL) {
45296 DUK_ASSERT(heap->dbg_detached_cb == NULL);
45297 return;
45298 }
45299
45300 /* Safe to call multiple times. */
45301
45302 detached_cb = heap->dbg_detached_cb;
45303 detached_udata = heap->dbg_udata;
45304 heap->dbg_detached_cb = NULL;
45305 heap->dbg_udata = NULL;
45306
45307 if (detached_cb) {
45308 /* Careful here: state must be wiped before the call
45309 * so that we can cleanly handle a re-attach from
45310 * inside the callback.
45311 */
45312 DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
45313 detached_cb(thr, detached_udata);
45314 }
45315
45316 heap->dbg_detaching = 0;
45317}
45318
45319DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
45320 duk__debug_do_detach1(heap, 0);
45321 duk__debug_do_detach2(heap);
45322}
45323
45324/* Called on a read/write error: NULL all callbacks except the detached
45325 * callback so that we never accidentally call them after a read/write
45326 * error has been indicated. This is especially important for the transport
45327 * I/O callbacks to fulfill guaranteed callback semantics.
45328 */
45329DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
45330 duk_heap *heap;
45331
45332 DUK_ASSERT(thr != NULL);
45333
45334 heap = thr->heap;
45335 DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
45336 heap->dbg_read_cb = NULL;
45337 heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */
45338 heap->dbg_peek_cb = NULL;
45339 heap->dbg_read_flush_cb = NULL;
45340 heap->dbg_write_flush_cb = NULL;
45341 heap->dbg_request_cb = NULL;
45342 /* keep heap->dbg_detached_cb */
45343}
45344
45345/*
45346 * Pause handling
45347 */
45348
45349DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) {
45350 duk_uint_fast32_t line;
45351
45352 line = duk_debug_curr_line(thr);
45353 if (line == 0) {
45354 /* No line info for current function. */
45355 duk_small_uint_t updated_flags;
45356
45357 updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE);
45358 DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx",
45359 (long) pause_flags, (long) updated_flags));
45360 pause_flags = updated_flags;
45361 }
45362
45363 heap->dbg_pause_flags = pause_flags;
45364 heap->dbg_pause_act = thr->callstack_curr;
45365 heap->dbg_pause_startline = (duk_uint32_t) line;
45366 heap->dbg_state_dirty = 1;
45367
45368 DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld",
45369 (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act,
45370 (long) heap->dbg_pause_startline));
45371}
45372
45373/*
45374 * Debug connection peek and flush primitives
45375 */
45376
45377DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
45378 duk_heap *heap;
45379 duk_bool_t ret;
45380
45381 DUK_ASSERT(thr != NULL);
45382 heap = thr->heap;
45383 DUK_ASSERT(heap != NULL);
45384
45385 if (heap->dbg_read_cb == NULL) {
45386 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
45387 return 0;
45388 }
45389 if (heap->dbg_peek_cb == NULL) {
45390 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
45391 return 0;
45392 }
45393
45394 DUK__DBG_TPORT_ENTER();
45395 ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
45396 DUK__DBG_TPORT_EXIT();
45397 return ret;
45398}
45399
45400DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
45401 duk_heap *heap;
45402
45403 DUK_ASSERT(thr != NULL);
45404 heap = thr->heap;
45405 DUK_ASSERT(heap != NULL);
45406
45407 if (heap->dbg_read_cb == NULL) {
45408 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
45409 return;
45410 }
45411 if (heap->dbg_read_flush_cb == NULL) {
45412 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
45413 return;
45414 }
45415
45416 DUK__DBG_TPORT_ENTER();
45417 heap->dbg_read_flush_cb(heap->dbg_udata);
45418 DUK__DBG_TPORT_EXIT();
45419}
45420
45421DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
45422 duk_heap *heap;
45423
45424 DUK_ASSERT(thr != NULL);
45425 heap = thr->heap;
45426 DUK_ASSERT(heap != NULL);
45427
45428 if (heap->dbg_read_cb == NULL) {
45429 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
45430 return;
45431 }
45432 if (heap->dbg_write_flush_cb == NULL) {
45433 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
45434 return;
45435 }
45436
45437 DUK__DBG_TPORT_ENTER();
45438 heap->dbg_write_flush_cb(heap->dbg_udata);
45439 DUK__DBG_TPORT_EXIT();
45440}
45441
45442/*
45443 * Debug connection skip primitives
45444 */
45445
45446/* Skip fully. */
45447DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
45448 duk_uint8_t dummy[64];
45449 duk_size_t now;
45450
45451 DUK_ASSERT(thr != NULL);
45452
45453 while (length > 0) {
45454 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
45455 duk_debug_read_bytes(thr, dummy, now);
45456 length -= now;
45457 }
45458}
45459
45460DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
45461 DUK_ASSERT(thr != NULL);
45462
45463 (void) duk_debug_read_byte(thr);
45464}
45465
45466/*
45467 * Debug connection read primitives
45468 */
45469
45470/* Peek ahead in the stream one byte. */
45471DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
45472 /* It is important not to call this if the last byte read was an EOM.
45473 * Reading ahead in this scenario would cause unnecessary blocking if
45474 * another message is not available.
45475 */
45476
45477 duk_uint8_t x;
45478
45479 x = duk_debug_read_byte(thr);
45480 thr->heap->dbg_have_next_byte = 1;
45481 thr->heap->dbg_next_byte = x;
45482 return x;
45483}
45484
45485/* Read fully. */
45486DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
45487 duk_heap *heap;
45488 duk_uint8_t *p;
45489 duk_size_t left;
45490 duk_size_t got;
45491
45492 DUK_ASSERT(thr != NULL);
45493 heap = thr->heap;
45494 DUK_ASSERT(heap != NULL);
45495 DUK_ASSERT(data != NULL);
45496
45497 if (heap->dbg_read_cb == NULL) {
45498 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
45499 goto fail;
45500 }
45501
45502 /* NOTE: length may be zero */
45503 p = data;
45504 if (length >= 1 && heap->dbg_have_next_byte) {
45505 heap->dbg_have_next_byte = 0;
45506 *p++ = heap->dbg_next_byte;
45507 }
45508 for (;;) {
45509 left = (duk_size_t) ((data + length) - p);
45510 if (left == 0) {
45511 break;
45512 }
45513 DUK_ASSERT(heap->dbg_read_cb != NULL);
45514 DUK_ASSERT(left >= 1);
45515#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
45516 left = 1;
45517#endif
45518 DUK__DBG_TPORT_ENTER();
45519 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
45520 DUK__DBG_TPORT_EXIT();
45521
45522 if (got == 0 || got > left) {
45523 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
45524 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
45525 DUK__SET_CONN_BROKEN(thr, 1);
45526 goto fail;
45527 }
45528 p += got;
45529 }
45530 return;
45531
45532 fail:
45533 duk_memzero((void *) data, (size_t) length);
45534}
45535
45536DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
45537 duk_uint8_t x;
45538
45539 x = 0; /* just in case callback is broken and won't write 'x' */
45540 duk_debug_read_bytes(thr, &x, 1);
45541 return x;
45542}
45543
45544DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
45545 duk_uint8_t buf[4];
45546
45547 DUK_ASSERT(thr != NULL);
45548
45549 duk_debug_read_bytes(thr, buf, 4);
45550 return ((duk_uint32_t) buf[0] << 24) |
45551 ((duk_uint32_t) buf[1] << 16) |
45552 ((duk_uint32_t) buf[2] << 8) |
45553 (duk_uint32_t) buf[3];
45554}
45555
45556DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) {
45557 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
45558}
45559
45560DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
45561 duk_uint8_t buf[2];
45562
45563 DUK_ASSERT(thr != NULL);
45564
45565 duk_debug_read_bytes(thr, buf, 2);
45566 return ((duk_uint16_t) buf[0] << 8) |
45567 (duk_uint16_t) buf[1];
45568}
45569
45570DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
45571 duk_small_uint_t x;
45572 duk_small_uint_t t;
45573
45574 DUK_ASSERT(thr != NULL);
45575
45576 x = duk_debug_read_byte(thr);
45577 if (x >= 0xc0) {
45578 t = duk_debug_read_byte(thr);
45579 return (duk_int32_t) (((x - 0xc0) << 8) + t);
45580 } else if (x >= 0x80) {
45581 return (duk_int32_t) (x - 0x80);
45582 } else if (x == DUK_DBG_IB_INT4) {
45583 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
45584 }
45585
45586 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
45587 DUK__SET_CONN_BROKEN(thr, 1);
45588 return 0;
45589}
45590
45591DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
45592 duk_uint8_t buf[31];
45593 duk_uint8_t *p;
45594
45595 if (len <= sizeof(buf)) {
45596 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
45597 duk_push_lstring(thr, (const char *) buf, (duk_size_t) len);
45598 } else {
45599 p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
45600 DUK_ASSERT(p != NULL);
45601 duk_debug_read_bytes(thr, p, (duk_size_t) len);
45602 (void) duk_buffer_to_string(thr, -1); /* Safety relies on debug client, which is OK. */
45603 }
45604
45605 return duk_require_hstring(thr, -1);
45606}
45607
45608DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
45609 duk_small_uint_t x;
45610 duk_uint32_t len;
45611
45612 DUK_ASSERT(thr != NULL);
45613
45614 x = duk_debug_read_byte(thr);
45615 if (x >= 0x60 && x <= 0x7f) {
45616 /* For short strings, use a fixed temp buffer. */
45617 len = (duk_uint32_t) (x - 0x60);
45618 } else if (x == DUK_DBG_IB_STR2) {
45619 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
45620 } else if (x == DUK_DBG_IB_STR4) {
45621 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
45622 } else {
45623 goto fail;
45624 }
45625
45626 return duk__debug_read_hstring_raw(thr, len);
45627
45628 fail:
45629 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
45630 DUK__SET_CONN_BROKEN(thr, 1);
45631 duk_push_hstring_empty(thr); /* always push some string */
45632 return duk_require_hstring(thr, -1);
45633}
45634
45635DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
45636 duk_uint8_t *p;
45637
45638 p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */
45639 DUK_ASSERT(p != NULL);
45640 duk_debug_read_bytes(thr, p, (duk_size_t) len);
45641
45642 return duk_require_hbuffer(thr, -1);
45643}
45644
45645DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
45646 duk_small_uint_t x;
45647 duk__ptr_union pu;
45648
45649 DUK_ASSERT(thr != NULL);
45650
45651 x = duk_debug_read_byte(thr);
45652 if (x != sizeof(pu)) {
45653 goto fail;
45654 }
45655 duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
45656#if defined(DUK_USE_INTEGER_LE)
45657 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
45658#endif
45659 return (void *) pu.p;
45660
45661 fail:
45662 DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
45663 DUK__SET_CONN_BROKEN(thr, 1);
45664 return (void *) NULL;
45665}
45666
45667DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
45668 duk_double_union du;
45669
45670 DUK_ASSERT(sizeof(du.uc) == 8);
45671 duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
45672 DUK_DBLUNION_DOUBLE_NTOH(&du);
45673 return du.d;
45674}
45675
45676#if 0
45677DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
45678 duk_small_uint_t x;
45679
45680 DUK_ASSERT(thr != NULL);
45681
45682 x = duk_debug_read_byte(thr);
45683 if (x != DUK_DBG_IB_HEAPPTR) {
45684 goto fail;
45685 }
45686
45687 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
45688
45689 fail:
45690 DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
45691 DUK__SET_CONN_BROKEN(thr, 1);
45692 return NULL;
45693}
45694#endif
45695
45696DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
45697 duk_small_uint_t x;
45698
45699 DUK_ASSERT(thr != NULL);
45700
45701 x = duk_debug_read_byte(thr);
45702 switch (x) {
45703 case DUK_DBG_IB_OBJECT:
45704 case DUK_DBG_IB_POINTER:
45705 case DUK_DBG_IB_HEAPPTR:
45706 /* Accept any pointer-like value; for 'object' dvalue, read
45707 * and ignore the class number.
45708 */
45709 if (x == DUK_DBG_IB_OBJECT) {
45710 duk_debug_skip_byte(thr);
45711 }
45712 break;
45713 default:
45714 goto fail;
45715 }
45716
45717 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
45718
45719 fail:
45720 DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
45721 DUK__SET_CONN_BROKEN(thr, 1);
45722 return NULL;
45723}
45724
45725DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
45726 duk_uint8_t x;
45727 duk_uint_t t;
45728 duk_uint32_t len;
45729
45730 DUK_ASSERT(thr != NULL);
45731
45732 x = duk_debug_read_byte(thr);
45733
45734 if (x >= 0xc0) {
45735 t = (duk_uint_t) (x - 0xc0);
45736 t = (t << 8) + duk_debug_read_byte(thr);
45737 duk_push_uint(thr, (duk_uint_t) t);
45738 goto return_ptr;
45739 }
45740 if (x >= 0x80) {
45741 duk_push_uint(thr, (duk_uint_t) (x - 0x80));
45742 goto return_ptr;
45743 }
45744 if (x >= 0x60) {
45745 len = (duk_uint32_t) (x - 0x60);
45746 duk__debug_read_hstring_raw(thr, len);
45747 goto return_ptr;
45748 }
45749
45750 switch (x) {
45751 case DUK_DBG_IB_INT4: {
45752 duk_int32_t i = duk__debug_read_int32_raw(thr);
45753 duk_push_i32(thr, i);
45754 break;
45755 }
45756 case DUK_DBG_IB_STR4: {
45757 len = duk__debug_read_uint32_raw(thr);
45758 duk__debug_read_hstring_raw(thr, len);
45759 break;
45760 }
45761 case DUK_DBG_IB_STR2: {
45762 len = duk__debug_read_uint16_raw(thr);
45763 duk__debug_read_hstring_raw(thr, len);
45764 break;
45765 }
45766 case DUK_DBG_IB_BUF4: {
45767 len = duk__debug_read_uint32_raw(thr);
45768 duk__debug_read_hbuffer_raw(thr, len);
45769 break;
45770 }
45771 case DUK_DBG_IB_BUF2: {
45772 len = duk__debug_read_uint16_raw(thr);
45773 duk__debug_read_hbuffer_raw(thr, len);
45774 break;
45775 }
45776 case DUK_DBG_IB_UNDEFINED: {
45777 duk_push_undefined(thr);
45778 break;
45779 }
45780 case DUK_DBG_IB_NULL: {
45781 duk_push_null(thr);
45782 break;
45783 }
45784 case DUK_DBG_IB_TRUE: {
45785 duk_push_true(thr);
45786 break;
45787 }
45788 case DUK_DBG_IB_FALSE: {
45789 duk_push_false(thr);
45790 break;
45791 }
45792 case DUK_DBG_IB_NUMBER: {
45793 duk_double_t d;
45794 d = duk__debug_read_double_raw(thr);
45795 duk_push_number(thr, d);
45796 break;
45797 }
45798 case DUK_DBG_IB_OBJECT: {
45799 duk_heaphdr *h;
45800 duk_debug_skip_byte(thr);
45801 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
45802 duk_push_heapptr(thr, (void *) h);
45803 break;
45804 }
45805 case DUK_DBG_IB_POINTER: {
45806 void *ptr;
45807 ptr = duk__debug_read_pointer_raw(thr);
45808 duk_push_pointer(thr, ptr);
45809 break;
45810 }
45811 case DUK_DBG_IB_LIGHTFUNC: {
45812 /* XXX: Not needed for now, so not implemented. Note that
45813 * function pointers may have different size/layout than
45814 * a void pointer.
45815 */
45816 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
45817 goto fail;
45818 }
45819 case DUK_DBG_IB_HEAPPTR: {
45820 duk_heaphdr *h;
45821 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
45822 duk_push_heapptr(thr, (void *) h);
45823 break;
45824 }
45825 case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */
45826 default:
45827 goto fail;
45828 }
45829
45830 return_ptr:
45831 return DUK_GET_TVAL_NEGIDX(thr, -1);
45832
45833 fail:
45834 DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
45835 DUK__SET_CONN_BROKEN(thr, 1);
45836 return NULL;
45837}
45838
45839/*
45840 * Debug connection write primitives
45841 */
45842
45843/* Write fully. */
45844DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
45845 duk_heap *heap;
45846 const duk_uint8_t *p;
45847 duk_size_t left;
45848 duk_size_t got;
45849
45850 DUK_ASSERT(thr != NULL);
45851 DUK_ASSERT(length == 0 || data != NULL);
45852 heap = thr->heap;
45853 DUK_ASSERT(heap != NULL);
45854
45855 if (heap->dbg_write_cb == NULL) {
45856 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
45857 return;
45858 }
45859 if (length == 0) {
45860 /* Avoid doing an actual write callback with length == 0,
45861 * because that's reserved for a write flush.
45862 */
45863 return;
45864 }
45865 DUK_ASSERT(data != NULL);
45866
45867 p = data;
45868 for (;;) {
45869 left = (duk_size_t) ((data + length) - p);
45870 if (left == 0) {
45871 break;
45872 }
45873 DUK_ASSERT(heap->dbg_write_cb != NULL);
45874 DUK_ASSERT(left >= 1);
45875#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
45876 left = 1;
45877#endif
45878 DUK__DBG_TPORT_ENTER();
45879 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
45880 DUK__DBG_TPORT_EXIT();
45881
45882 if (got == 0 || got > left) {
45883 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
45884 DUK_D(DUK_DPRINT("connection error during write"));
45885 DUK__SET_CONN_BROKEN(thr, 1);
45886 return;
45887 }
45888 p += got;
45889 }
45890}
45891
45892DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
45893 duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
45894}
45895
45896DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
45897 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
45898}
45899
45900DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
45901 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
45902}
45903
45904#if defined(DUK_USE_DEBUGGER_INSPECT)
45905DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
45906 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
45907}
45908#endif
45909
45910DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
45911 duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
45912}
45913
45914/* Write signed 32-bit integer. */
45915DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
45916 duk_uint8_t buf[5];
45917 duk_size_t len;
45918
45919 DUK_ASSERT(thr != NULL);
45920
45921 if (x >= 0 && x <= 0x3fL) {
45922 buf[0] = (duk_uint8_t) (0x80 + x);
45923 len = 1;
45924 } else if (x >= 0 && x <= 0x3fffL) {
45925 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
45926 buf[1] = (duk_uint8_t) (x & 0xff);
45927 len = 2;
45928 } else {
45929 /* Signed integers always map to 4 bytes now. */
45930 buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
45931 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
45932 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
45933 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
45934 buf[4] = (duk_uint8_t) (x & 0xff);
45935 len = 5;
45936 }
45937 duk_debug_write_bytes(thr, buf, len);
45938}
45939
45940/* Write unsigned 32-bit integer. */
45941DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
45942 /* The debugger protocol doesn't support a plain integer encoding for
45943 * the full 32-bit unsigned range (only 32-bit signed). For now,
45944 * unsigned 32-bit values simply written as signed ones. This is not
45945 * a concrete issue except for 32-bit heaphdr fields. Proper solutions
45946 * would be to (a) write such integers as IEEE doubles or (b) add an
45947 * unsigned 32-bit dvalue.
45948 */
45949 if (x >= 0x80000000UL) {
45950 DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
45951 (long) x));
45952 }
45953 duk_debug_write_int(thr, (duk_int32_t) x);
45954}
45955
45956DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
45957 duk_uint8_t buf[5];
45958 duk_size_t buflen;
45959
45960 DUK_ASSERT(thr != NULL);
45961 DUK_ASSERT(length == 0 || data != NULL);
45962
45963 if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
45964 /* For strings, special form for short lengths. */
45965 buf[0] = (duk_uint8_t) (0x60 + length);
45966 buflen = 1;
45967 } else if (length <= 0xffffUL) {
45968 buf[0] = (duk_uint8_t) (marker_base + 1);
45969 buf[1] = (duk_uint8_t) (length >> 8);
45970 buf[2] = (duk_uint8_t) (length & 0xff);
45971 buflen = 3;
45972 } else {
45973 buf[0] = (duk_uint8_t) marker_base;
45974 buf[1] = (duk_uint8_t) (length >> 24);
45975 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
45976 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
45977 buf[4] = (duk_uint8_t) (length & 0xff);
45978 buflen = 5;
45979 }
45980
45981 duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
45982 duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
45983}
45984
45985DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
45986 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
45987}
45988
45989DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
45990 DUK_ASSERT(thr != NULL);
45991
45992 duk_debug_write_string(thr,
45993 data,
45994 data ? DUK_STRLEN(data) : 0);
45995}
45996
45997DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
45998 DUK_ASSERT(thr != NULL);
45999
46000 /* XXX: differentiate null pointer from empty string? */
46001 duk_debug_write_string(thr,
46002 (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
46003 (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
46004}
46005
46006DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
46007 duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1));
46008}
46009
46010DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
46011 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
46012}
46013
46014DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
46015 DUK_ASSERT(thr != NULL);
46016
46017 duk_debug_write_buffer(thr,
46018 (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
46019 (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
46020}
46021
46022DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
46023 duk_uint8_t buf[2];
46024 duk__ptr_union pu;
46025
46026 DUK_ASSERT(thr != NULL);
46027 DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
46028 /* ptr may be NULL */
46029
46030 buf[0] = ibyte;
46031 buf[1] = sizeof(pu);
46032 duk_debug_write_bytes(thr, buf, 2);
46033 pu.p = (void *) ptr;
46034#if defined(DUK_USE_INTEGER_LE)
46035 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
46036#endif
46037 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
46038}
46039
46040DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
46041 duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
46042}
46043
46044#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
46045DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
46046 duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
46047}
46048#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
46049
46050DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
46051 duk_uint8_t buf[3];
46052 duk__ptr_union pu;
46053
46054 DUK_ASSERT(thr != NULL);
46055 DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
46056 DUK_ASSERT(obj != NULL);
46057
46058 buf[0] = DUK_DBG_IB_OBJECT;
46059 buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
46060 buf[2] = sizeof(pu);
46061 duk_debug_write_bytes(thr, buf, 3);
46062 pu.p = (void *) obj;
46063#if defined(DUK_USE_INTEGER_LE)
46064 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
46065#endif
46066 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
46067}
46068
46069DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
46070 duk_c_function lf_func;
46071 duk_small_uint_t lf_flags;
46072 duk_uint8_t buf[4];
46073 duk_double_union du1;
46074 duk_double_union du2;
46075 duk_int32_t i32;
46076
46077 DUK_ASSERT(thr != NULL);
46078 DUK_ASSERT(tv != NULL);
46079
46080 switch (DUK_TVAL_GET_TAG(tv)) {
46081 case DUK_TAG_UNDEFINED:
46082 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
46083 break;
46084 case DUK_TAG_UNUSED:
46085 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
46086 break;
46087 case DUK_TAG_NULL:
46088 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
46089 break;
46090 case DUK_TAG_BOOLEAN:
46091 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
46092 DUK_TVAL_GET_BOOLEAN(tv) == 1);
46093 duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
46094 break;
46095 case DUK_TAG_POINTER:
46096 duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
46097 break;
46098 case DUK_TAG_LIGHTFUNC:
46099 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
46100 buf[0] = DUK_DBG_IB_LIGHTFUNC;
46101 buf[1] = (duk_uint8_t) (lf_flags >> 8);
46102 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
46103 buf[3] = sizeof(lf_func);
46104 duk_debug_write_bytes(thr, buf, 4);
46105 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
46106 break;
46107 case DUK_TAG_STRING:
46108 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
46109 break;
46110 case DUK_TAG_OBJECT:
46111 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
46112 break;
46113 case DUK_TAG_BUFFER:
46114 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
46115 break;
46116#if defined(DUK_USE_FASTINT)
46117 case DUK_TAG_FASTINT:
46118#endif
46119 default:
46120 /* Numbers are normalized to big (network) endian. We can
46121 * (but are not required) to use integer dvalues when there's
46122 * no loss of precision.
46123 *
46124 * XXX: share check with other code; this check is slow but
46125 * reliable and doesn't require careful exponent/mantissa
46126 * mask tricks as in the fastint downgrade code.
46127 */
46128 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
46129 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
46130 du1.d = DUK_TVAL_GET_NUMBER(tv);
46131 i32 = (duk_int32_t) du1.d;
46132 du2.d = (duk_double_t) i32;
46133
46134 DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
46135 "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
46136 (long) i32,
46137 (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
46138 (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
46139 (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
46140 (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
46141 (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
46142 (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
46143 (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
46144 (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
46145
46146 if (duk_memcmp((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
46147 duk_debug_write_int(thr, i32);
46148 } else {
46149 DUK_DBLUNION_DOUBLE_HTON(&du1);
46150 duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
46151 duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
46152 }
46153 }
46154}
46155
46156#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
46157/* Variant for writing duk_tvals so that any heap allocated values are
46158 * written out as tagged heap pointers.
46159 */
46160DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
46161 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
46162 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
46163 duk_debug_write_heapptr(thr, h);
46164 } else {
46165 duk_debug_write_tval(thr, tv);
46166 }
46167}
46168#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
46169
46170/*
46171 * Debug connection message write helpers
46172 */
46173
46174#if 0 /* unused */
46175DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
46176 duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
46177 duk_debug_write_int(thr, command);
46178}
46179#endif
46180
46181DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
46182 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
46183}
46184
46185DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
46186 /* Allow NULL 'msg' */
46187 duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
46188 duk_debug_write_int(thr, (duk_int32_t) err_code);
46189 duk_debug_write_cstring(thr, msg);
46190 duk_debug_write_eom(thr);
46191}
46192
46193DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
46194 duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
46195 duk_debug_write_int(thr, (duk_int32_t) command);
46196}
46197
46198DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
46199 duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
46200
46201 /* As an initial implementation, write flush after every EOM (and the
46202 * version identifier). A better implementation would flush only when
46203 * Duktape is finished processing messages so that a flush only happens
46204 * after all outbound messages are finished on that occasion.
46205 */
46206 duk_debug_write_flush(thr);
46207}
46208
46209/*
46210 * Status message and helpers
46211 */
46212
46213DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
46214 duk_activation *act;
46215 duk_uint_fast32_t line;
46216 duk_uint_fast32_t pc;
46217
46218 act = thr->callstack_curr;
46219 if (act == NULL) {
46220 return 0;
46221 }
46222
46223 /* We're conceptually between two opcodes; act->pc indicates the next
46224 * instruction to be executed. This is usually the correct pc/line to
46225 * indicate in Status. (For the 'debugger' statement this now reports
46226 * the pc/line after the debugger statement because the debugger opcode
46227 * has already been executed.)
46228 */
46229
46230 pc = duk_hthread_get_act_curr_pc(thr, act);
46231
46232 /* XXX: this should be optimized to be a raw query and avoid valstack
46233 * operations if possible.
46234 */
46235 duk_push_tval(thr, &act->tv_func);
46236 line = duk_hobject_pc2line_query(thr, -1, pc);
46237 duk_pop(thr);
46238 return line;
46239}
46240
46241DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
46242 duk_activation *act;
46243
46244 duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
46245 duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0));
46246
46247 act = thr->callstack_curr;
46248 if (act == NULL) {
46249 duk_debug_write_undefined(thr);
46250 duk_debug_write_undefined(thr);
46251 duk_debug_write_int(thr, 0);
46252 duk_debug_write_int(thr, 0);
46253 } else {
46254 duk_push_tval(thr, &act->tv_func);
46255 duk_get_prop_literal(thr, -1, "fileName");
46256 duk__debug_write_hstring_safe_top(thr);
46257 duk_get_prop_literal(thr, -2, "name");
46258 duk__debug_write_hstring_safe_top(thr);
46259 duk_pop_3(thr);
46260 /* Report next pc/line to be executed. */
46261 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
46262 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
46263 }
46264
46265 duk_debug_write_eom(thr);
46266}
46267
46268#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
46269DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
46270 /*
46271 * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
46272 */
46273
46274 duk_activation *act;
46275 duk_uint32_t pc;
46276
46277 DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
46278
46279 duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
46280 duk_debug_write_int(thr, (duk_int32_t) fatal);
46281
46282 /* Report thrown value to client coerced to string */
46283 duk_dup_top(thr);
46284 duk__debug_write_hstring_safe_top(thr);
46285 duk_pop(thr);
46286
46287 if (duk_is_error(thr, -1)) {
46288 /* Error instance, use augmented error data directly */
46289 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
46290 duk__debug_write_hstring_safe_top(thr);
46291 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER);
46292 duk_debug_write_uint(thr, duk_get_uint(thr, -1));
46293 duk_pop_2(thr);
46294 } else {
46295 /* For anything other than an Error instance, we calculate the
46296 * error location directly from the current activation if one
46297 * exists.
46298 */
46299 act = thr->callstack_curr;
46300 if (act != NULL) {
46301 duk_push_tval(thr, &act->tv_func);
46302 duk_get_prop_literal(thr, -1, "fileName");
46303 duk__debug_write_hstring_safe_top(thr);
46304 pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act);
46305 duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc));
46306 duk_pop_2(thr);
46307 } else {
46308 /* Can happen if duk_throw() is called on an empty
46309 * callstack.
46310 */
46311 duk_debug_write_cstring(thr, "");
46312 duk_debug_write_uint(thr, 0);
46313 }
46314 }
46315
46316 duk_debug_write_eom(thr);
46317}
46318#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */
46319
46320/*
46321 * Debug message processing
46322 */
46323
46324/* Skip dvalue. */
46325DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
46326 duk_uint8_t x;
46327 duk_uint32_t len;
46328
46329 x = duk_debug_read_byte(thr);
46330
46331 if (x >= 0xc0) {
46332 duk_debug_skip_byte(thr);
46333 return 0;
46334 }
46335 if (x >= 0x80) {
46336 return 0;
46337 }
46338 if (x >= 0x60) {
46339 duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60));
46340 return 0;
46341 }
46342 switch(x) {
46343 case DUK_DBG_IB_EOM:
46344 return 1; /* Return 1: got EOM */
46345 case DUK_DBG_IB_REQUEST:
46346 case DUK_DBG_IB_REPLY:
46347 case DUK_DBG_IB_ERROR:
46348 case DUK_DBG_IB_NOTIFY:
46349 break;
46350 case DUK_DBG_IB_INT4:
46351 (void) duk__debug_read_uint32_raw(thr);
46352 break;
46353 case DUK_DBG_IB_STR4:
46354 case DUK_DBG_IB_BUF4:
46355 len = duk__debug_read_uint32_raw(thr);
46356 duk_debug_skip_bytes(thr, len);
46357 break;
46358 case DUK_DBG_IB_STR2:
46359 case DUK_DBG_IB_BUF2:
46360 len = duk__debug_read_uint16_raw(thr);
46361 duk_debug_skip_bytes(thr, len);
46362 break;
46363 case DUK_DBG_IB_UNUSED:
46364 case DUK_DBG_IB_UNDEFINED:
46365 case DUK_DBG_IB_NULL:
46366 case DUK_DBG_IB_TRUE:
46367 case DUK_DBG_IB_FALSE:
46368 break;
46369 case DUK_DBG_IB_NUMBER:
46370 duk_debug_skip_bytes(thr, 8);
46371 break;
46372 case DUK_DBG_IB_OBJECT:
46373 duk_debug_skip_byte(thr);
46374 len = duk_debug_read_byte(thr);
46375 duk_debug_skip_bytes(thr, len);
46376 break;
46377 case DUK_DBG_IB_POINTER:
46378 case DUK_DBG_IB_HEAPPTR:
46379 len = duk_debug_read_byte(thr);
46380 duk_debug_skip_bytes(thr, len);
46381 break;
46382 case DUK_DBG_IB_LIGHTFUNC:
46383 duk_debug_skip_bytes(thr, 2);
46384 len = duk_debug_read_byte(thr);
46385 duk_debug_skip_bytes(thr, len);
46386 break;
46387 default:
46388 goto fail;
46389 }
46390
46391 return 0;
46392
46393 fail:
46394 DUK__SET_CONN_BROKEN(thr, 1);
46395 return 1; /* Pretend like we got EOM */
46396}
46397
46398/* Skip dvalues to EOM. */
46399DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
46400 for (;;) {
46401 if (duk__debug_skip_dvalue(thr)) {
46402 break;
46403 }
46404 }
46405}
46406
46407/* Read and validate a call stack index. If index is invalid, write out an
46408 * error message and return zero.
46409 */
46410DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
46411 duk_int32_t level;
46412 level = duk_debug_read_int(thr);
46413 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
46414 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
46415 return 0; /* zero indicates failure */
46416 }
46417 return level;
46418}
46419
46420/* Read a call stack index and lookup the corresponding duk_activation.
46421 * If index is invalid, write out an error message and return NULL.
46422 */
46423DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) {
46424 duk_activation *act;
46425 duk_int32_t level;
46426
46427 level = duk_debug_read_int(thr);
46428 act = duk_hthread_get_activation_for_level(thr, level);
46429 if (act == NULL) {
46430 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
46431 }
46432 return act;
46433}
46434
46435/*
46436 * Simple commands
46437 */
46438
46439DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
46440 DUK_UNREF(heap);
46441 DUK_D(DUK_DPRINT("debug command Version"));
46442
46443 duk_debug_write_reply(thr);
46444 duk_debug_write_int(thr, DUK_VERSION);
46445 duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
46446 duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
46447#if defined(DUK_USE_DOUBLE_LE)
46448 duk_debug_write_int(thr, 1);
46449#elif defined(DUK_USE_DOUBLE_ME)
46450 duk_debug_write_int(thr, 2);
46451#elif defined(DUK_USE_DOUBLE_BE)
46452 duk_debug_write_int(thr, 3);
46453#else
46454 duk_debug_write_int(thr, 0);
46455#endif
46456 duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
46457 duk_debug_write_eom(thr);
46458}
46459
46460DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
46461 DUK_UNREF(heap);
46462 DUK_D(DUK_DPRINT("debug command TriggerStatus"));
46463
46464 duk_debug_write_reply(thr);
46465 duk_debug_write_eom(thr);
46466 heap->dbg_state_dirty = 1;
46467}
46468
46469DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
46470 DUK_D(DUK_DPRINT("debug command Pause"));
46471 duk_debug_set_paused(heap);
46472 duk_debug_write_reply(thr);
46473 duk_debug_write_eom(thr);
46474}
46475
46476DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
46477 duk_small_uint_t pause_flags;
46478
46479 DUK_D(DUK_DPRINT("debug command Resume"));
46480
46481 duk_debug_clear_paused(heap);
46482
46483 pause_flags = 0;
46484#if 0 /* manual testing */
46485 pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE;
46486 pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR;
46487 pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
46488#endif
46489#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
46490 pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
46491#endif
46492
46493 duk__debug_set_pause_state(thr, heap, pause_flags);
46494
46495 duk_debug_write_reply(thr);
46496 duk_debug_write_eom(thr);
46497}
46498
46499DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
46500 duk_small_uint_t pause_flags;
46501
46502 DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
46503
46504 if (cmd == DUK_DBG_CMD_STEPINTO) {
46505 pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
46506 DUK_PAUSE_FLAG_FUNC_ENTRY |
46507 DUK_PAUSE_FLAG_FUNC_EXIT;
46508 } else if (cmd == DUK_DBG_CMD_STEPOVER) {
46509 pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
46510 DUK_PAUSE_FLAG_FUNC_EXIT;
46511 } else {
46512 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
46513 pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT;
46514 }
46515#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
46516 pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
46517#endif
46518
46519 /* If current activation doesn't have line information, line-based
46520 * pause flags are automatically disabled. As a result, e.g.
46521 * StepInto will then pause on (native) function entry or exit.
46522 */
46523 duk_debug_clear_paused(heap);
46524 duk__debug_set_pause_state(thr, heap, pause_flags);
46525
46526 duk_debug_write_reply(thr);
46527 duk_debug_write_eom(thr);
46528}
46529
46530DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
46531 duk_small_int_t i;
46532
46533 DUK_D(DUK_DPRINT("debug command ListBreak"));
46534 duk_debug_write_reply(thr);
46535 for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
46536 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
46537 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
46538 }
46539 duk_debug_write_eom(thr);
46540}
46541
46542DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
46543 duk_hstring *filename;
46544 duk_uint32_t linenumber;
46545 duk_small_int_t idx;
46546
46547 DUK_UNREF(heap);
46548
46549 filename = duk_debug_read_hstring(thr);
46550 linenumber = (duk_uint32_t) duk_debug_read_int(thr);
46551 DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
46552 idx = duk_debug_add_breakpoint(thr, filename, linenumber);
46553 if (idx >= 0) {
46554 duk_debug_write_reply(thr);
46555 duk_debug_write_int(thr, (duk_int32_t) idx);
46556 duk_debug_write_eom(thr);
46557 } else {
46558 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
46559 }
46560}
46561
46562DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
46563 duk_small_uint_t idx;
46564
46565 DUK_UNREF(heap);
46566
46567 DUK_D(DUK_DPRINT("debug command DelBreak"));
46568 idx = (duk_small_uint_t) duk_debug_read_int(thr);
46569 if (duk_debug_remove_breakpoint(thr, idx)) {
46570 duk_debug_write_reply(thr);
46571 duk_debug_write_eom(thr);
46572 } else {
46573 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
46574 }
46575}
46576
46577DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
46578 duk_activation *act;
46579 duk_hstring *str;
46580 duk_bool_t rc;
46581
46582 DUK_UNREF(heap);
46583 DUK_D(DUK_DPRINT("debug command GetVar"));
46584
46585 act = duk__debug_read_level_get_activation(thr);
46586 if (act == NULL) {
46587 return;
46588 }
46589 str = duk_debug_read_hstring(thr); /* push to stack */
46590 DUK_ASSERT(str != NULL);
46591
46592 rc = duk_js_getvar_activation(thr, act, str, 0);
46593
46594 duk_debug_write_reply(thr);
46595 if (rc) {
46596 duk_debug_write_int(thr, 1);
46597 DUK_ASSERT(duk_get_tval(thr, -2) != NULL);
46598 duk_debug_write_tval(thr, duk_get_tval(thr, -2));
46599 } else {
46600 duk_debug_write_int(thr, 0);
46601 duk_debug_write_unused(thr);
46602 }
46603 duk_debug_write_eom(thr);
46604}
46605
46606DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
46607 duk_activation *act;
46608 duk_hstring *str;
46609 duk_tval *tv;
46610
46611 DUK_UNREF(heap);
46612 DUK_D(DUK_DPRINT("debug command PutVar"));
46613
46614 act = duk__debug_read_level_get_activation(thr);
46615 if (act == NULL) {
46616 return;
46617 }
46618 str = duk_debug_read_hstring(thr); /* push to stack */
46619 DUK_ASSERT(str != NULL);
46620 tv = duk_debug_read_tval(thr);
46621 if (tv == NULL) {
46622 /* detached */
46623 return;
46624 }
46625
46626 duk_js_putvar_activation(thr, act, str, tv, 0);
46627
46628 /* XXX: Current putvar implementation doesn't have a success flag,
46629 * add one and send to debug client?
46630 */
46631 duk_debug_write_reply(thr);
46632 duk_debug_write_eom(thr);
46633}
46634
46635DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
46636 duk_hthread *curr_thr = thr;
46637 duk_activation *curr_act;
46638 duk_uint_fast32_t pc;
46639 duk_uint_fast32_t line;
46640
46641 DUK_ASSERT(thr != NULL);
46642 DUK_UNREF(heap);
46643
46644 duk_debug_write_reply(thr);
46645 while (curr_thr != NULL) {
46646 for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) {
46647 /* PC/line semantics here are:
46648 * - For callstack top we're conceptually between two
46649 * opcodes and current PC indicates next line to
46650 * execute, so report that (matches Status).
46651 * - For other activations we're conceptually still
46652 * executing the instruction at PC-1, so report that
46653 * (matches error stacktrace behavior).
46654 * - See: https://github.com/svaarala/duktape/issues/281
46655 */
46656
46657 /* XXX: optimize to use direct reads, i.e. avoid
46658 * value stack operations.
46659 */
46660 duk_push_tval(thr, &curr_act->tv_func);
46661 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
46662 duk__debug_write_hstring_safe_top(thr);
46663 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
46664 duk__debug_write_hstring_safe_top(thr);
46665 pc = duk_hthread_get_act_curr_pc(thr, curr_act);
46666 if (curr_act != curr_thr->callstack_curr && pc > 0) {
46667 pc--;
46668 }
46669 line = duk_hobject_pc2line_query(thr, -3, pc);
46670 duk_debug_write_uint(thr, (duk_uint32_t) line);
46671 duk_debug_write_uint(thr, (duk_uint32_t) pc);
46672 duk_pop_3(thr);
46673 }
46674 curr_thr = curr_thr->resumer;
46675 }
46676 /* SCANBUILD: warning about 'thr' potentially being NULL here,
46677 * warning is incorrect because thr != NULL always here.
46678 */
46679 duk_debug_write_eom(thr);
46680}
46681
46682DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
46683 duk_activation *act;
46684 duk_hstring *varname;
46685
46686 DUK_UNREF(heap);
46687
46688 act = duk__debug_read_level_get_activation(thr);
46689 if (act == NULL) {
46690 return;
46691 }
46692
46693 duk_debug_write_reply(thr);
46694
46695 /* XXX: several nice-to-have improvements here:
46696 * - Use direct reads avoiding value stack operations
46697 * - Avoid triggering getters, indicate getter values to debug client
46698 * - If side effects are possible, add error catching
46699 */
46700
46701 if (DUK_TVAL_IS_OBJECT(&act->tv_func)) {
46702 duk_hobject *h_func = DUK_TVAL_GET_OBJECT(&act->tv_func);
46703 duk_hobject *h_varmap;
46704
46705 h_varmap = duk_hobject_get_varmap(thr, h_func);
46706 if (h_varmap != NULL) {
46707 duk_push_hobject(thr, h_varmap);
46708 duk_enum(thr, -1, 0 /*enum_flags*/);
46709 while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
46710 varname = duk_known_hstring(thr, -1);
46711
46712 duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/);
46713 /* [ ... func varmap enum key value this ] */
46714 duk_debug_write_hstring(thr, duk_get_hstring(thr, -3));
46715 duk_debug_write_tval(thr, duk_get_tval(thr, -2));
46716 duk_pop_3(thr); /* -> [ ... func varmap enum ] */
46717 }
46718 } else {
46719 DUK_D(DUK_DPRINT("varmap missing in GetLocals, ignore"));
46720 }
46721 } else {
46722 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
46723 }
46724
46725 duk_debug_write_eom(thr);
46726}
46727
46728DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
46729 duk_small_uint_t call_flags;
46730 duk_int_t call_ret;
46731 duk_small_int_t eval_err;
46732 duk_bool_t direct_eval;
46733 duk_int32_t level;
46734 duk_idx_t idx_func;
46735
46736 DUK_UNREF(heap);
46737
46738 DUK_D(DUK_DPRINT("debug command Eval"));
46739
46740 /* The eval code is executed within the lexical environment of a specified
46741 * activation. For now, use global object eval() function, with the eval
46742 * considered a 'direct call to eval'.
46743 *
46744 * Callstack index for debug commands only affects scope -- the callstack
46745 * as seen by, e.g. Duktape.act() will be the same regardless.
46746 */
46747
46748 /* nargs == 2 so we can pass a callstack index to eval(). */
46749 idx_func = duk_get_top(thr);
46750 duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/);
46751 duk_push_undefined(thr); /* 'this' binding shouldn't matter here */
46752
46753 /* Read callstack index, if non-null. */
46754 if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) {
46755 direct_eval = 0;
46756 level = -1; /* Not needed, but silences warning. */
46757 (void) duk_debug_read_byte(thr);
46758 } else {
46759 direct_eval = 1;
46760 level = duk__debug_read_validate_csindex(thr);
46761 if (level == 0) {
46762 return;
46763 }
46764 }
46765
46766 DUK_ASSERT(!direct_eval ||
46767 (level < 0 && -level <= (duk_int32_t) thr->callstack_top));
46768
46769 (void) duk_debug_read_hstring(thr);
46770 if (direct_eval) {
46771 duk_push_int(thr, level - 1); /* compensate for eval() call */
46772 }
46773
46774 /* [ ... eval "eval" eval_input level? ] */
46775
46776 call_flags = 0;
46777 if (direct_eval) {
46778 duk_activation *act;
46779 duk_hobject *fun;
46780
46781 act = duk_hthread_get_activation_for_level(thr, level);
46782 if (act != NULL) {
46783 fun = DUK_ACT_GET_FUNC(act);
46784 if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) {
46785 /* Direct eval requires that there's a current
46786 * activation and it is an ECMAScript function.
46787 * When Eval is executed from e.g. cooperate API
46788 * call we'll need to do an indirect eval instead.
46789 */
46790 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
46791 }
46792 }
46793 }
46794
46795 call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags);
46796
46797 if (call_ret == DUK_EXEC_SUCCESS) {
46798 eval_err = 0;
46799 /* Use result value as is. */
46800 } else {
46801 /* For errors a string coerced result is most informative
46802 * right now, as the debug client doesn't have the capability
46803 * to traverse the error object.
46804 */
46805 eval_err = 1;
46806 duk_safe_to_string(thr, -1);
46807 }
46808
46809 /* [ ... result ] */
46810
46811 duk_debug_write_reply(thr);
46812 duk_debug_write_int(thr, (duk_int32_t) eval_err);
46813 DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
46814 duk_debug_write_tval(thr, duk_get_tval(thr, -1));
46815 duk_debug_write_eom(thr);
46816}
46817
46818DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
46819 DUK_UNREF(heap);
46820 DUK_D(DUK_DPRINT("debug command Detach"));
46821
46822 duk_debug_write_reply(thr);
46823 duk_debug_write_eom(thr);
46824
46825 DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
46826 DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
46827}
46828
46829DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
46830 duk_idx_t old_top;
46831
46832 DUK_D(DUK_DPRINT("debug command AppRequest"));
46833
46834 old_top = duk_get_top(thr); /* save stack top */
46835
46836 if (heap->dbg_request_cb != NULL) {
46837 duk_idx_t nrets;
46838 duk_idx_t nvalues = 0;
46839 duk_idx_t top, idx;
46840
46841 /* Read tvals from the message and push them onto the valstack,
46842 * then call the request callback to process the request.
46843 */
46844 while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
46845 duk_tval *tv;
46846 if (!duk_check_stack(thr, 1)) {
46847 DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
46848 goto fail;
46849 }
46850 tv = duk_debug_read_tval(thr); /* push to stack */
46851 if (tv == NULL) {
46852 /* detached */
46853 return;
46854 }
46855 nvalues++;
46856 }
46857 DUK_ASSERT(duk_get_top(thr) == old_top + nvalues);
46858
46859 /* Request callback should push values for reply to client onto valstack */
46860 DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
46861 (long) nvalues, (long) old_top, (long) duk_get_top(thr)));
46862 nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues);
46863 DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
46864 (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr)));
46865 if (nrets >= 0) {
46866 DUK_ASSERT(duk_get_top(thr) >= old_top + nrets);
46867 if (duk_get_top(thr) < old_top + nrets) {
46868 DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
46869 "top=%ld < old_top=%ld + nrets=%ld; "
46870 "this might mean it's unsafe to continue!",
46871 (long) duk_get_top(thr), (long) old_top, (long) nrets));
46872 goto fail;
46873 }
46874
46875 /* Reply with tvals pushed by request callback */
46876 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
46877 top = duk_get_top(thr);
46878 for (idx = top - nrets; idx < top; idx++) {
46879 duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx));
46880 }
46881 duk_debug_write_eom(thr);
46882 } else {
46883 DUK_ASSERT(duk_get_top(thr) >= old_top + 1);
46884 if (duk_get_top(thr) < old_top + 1) {
46885 DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
46886 goto fail;
46887 }
46888 duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1));
46889 }
46890
46891 duk_set_top(thr, old_top); /* restore stack top */
46892 } else {
46893 DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
46894 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
46895 }
46896
46897 return;
46898
46899 fail:
46900 duk_set_top(thr, old_top); /* restore stack top */
46901 DUK__SET_CONN_BROKEN(thr, 1);
46902}
46903
46904/*
46905 * DumpHeap command
46906 */
46907
46908#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
46909/* XXX: this has some overlap with object inspection; remove this and make
46910 * DumpHeap return lists of heapptrs instead?
46911 */
46912DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
46913 DUK_UNREF(heap);
46914
46915 duk_debug_write_heapptr(thr, hdr);
46916 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
46917 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
46918#if defined(DUK_USE_REFERENCE_COUNTING)
46919 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
46920#else
46921 duk_debug_write_int(thr, (duk_int32_t) -1);
46922#endif
46923
46924 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
46925 case DUK_HTYPE_STRING: {
46926 duk_hstring *h = (duk_hstring *) hdr;
46927
46928 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h));
46929 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h));
46930 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
46931 duk_debug_write_hstring(thr, h);
46932 break;
46933 }
46934 case DUK_HTYPE_OBJECT: {
46935 duk_hobject *h = (duk_hobject *) hdr;
46936 duk_hstring *k;
46937 duk_uint_fast32_t i;
46938
46939 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
46940 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
46941 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
46942 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
46943 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
46944 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
46945
46946 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
46947 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
46948 k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
46949 duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
46950 if (k == NULL) {
46951 duk_debug_write_int(thr, 0); /* isAccessor */
46952 duk_debug_write_unused(thr);
46953 continue;
46954 }
46955 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
46956 duk_debug_write_int(thr, 1); /* isAccessor */
46957 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
46958 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
46959 } else {
46960 duk_debug_write_int(thr, 0); /* isAccessor */
46961
46962 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
46963 }
46964 }
46965
46966 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
46967 /* Note: array dump will include elements beyond
46968 * 'length'.
46969 */
46970 duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
46971 }
46972 break;
46973 }
46974 case DUK_HTYPE_BUFFER: {
46975 duk_hbuffer *h = (duk_hbuffer *) hdr;
46976
46977 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
46978 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
46979 break;
46980 }
46981 default: {
46982 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
46983 }
46984 }
46985}
46986
46987DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
46988 duk_heaphdr *hdr;
46989
46990 hdr = heap->heap_allocated;
46991 while (hdr != NULL) {
46992 duk__debug_dump_heaphdr(thr, heap, hdr);
46993 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
46994 }
46995}
46996
46997DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) {
46998 duk_uint32_t i;
46999 duk_hstring *h;
47000
47001 for (i = 0; i < heap->st_size; i++) {
47002#if defined(DUK_USE_STRTAB_PTRCOMP)
47003 h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
47004#else
47005 h = heap->strtable[i];
47006#endif
47007 while (h != NULL) {
47008 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
47009 h = h->hdr.h_next;
47010 }
47011 }
47012}
47013
47014DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
47015 DUK_D(DUK_DPRINT("debug command DumpHeap"));
47016
47017 duk_debug_write_reply(thr);
47018 duk__debug_dump_heap_allocated(thr, heap);
47019 duk__debug_dump_strtab(thr, heap);
47020 duk_debug_write_eom(thr);
47021}
47022#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
47023
47024DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
47025 duk_activation *act;
47026 duk_hcompfunc *fun = NULL;
47027 duk_size_t i, n;
47028 duk_tval *tv;
47029 duk_hobject **fn;
47030 duk_int32_t level = -1;
47031 duk_uint8_t ibyte;
47032
47033 DUK_UNREF(heap);
47034
47035 DUK_D(DUK_DPRINT("debug command GetBytecode"));
47036
47037 ibyte = duk_debug_peek_byte(thr);
47038 if (ibyte != DUK_DBG_IB_EOM) {
47039 tv = duk_debug_read_tval(thr);
47040 if (tv == NULL) {
47041 /* detached */
47042 return;
47043 }
47044 if (DUK_TVAL_IS_OBJECT(tv)) {
47045 /* tentative, checked later */
47046 fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv);
47047 DUK_ASSERT(fun != NULL);
47048 } else if (DUK_TVAL_IS_NUMBER(tv)) {
47049 level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
47050 } else {
47051 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
47052 goto fail_args;
47053 }
47054 }
47055
47056 if (fun == NULL) {
47057 act = duk_hthread_get_activation_for_level(thr, level);
47058 if (act == NULL) {
47059 goto fail_index;
47060 }
47061 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
47062 }
47063
47064 if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) {
47065 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
47066 goto fail_args;
47067 }
47068 DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun));
47069
47070 duk_debug_write_reply(thr);
47071 n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun);
47072 duk_debug_write_int(thr, (duk_int32_t) n);
47073 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun);
47074 for (i = 0; i < n; i++) {
47075 duk_debug_write_tval(thr, tv);
47076 tv++;
47077 }
47078 n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun);
47079 duk_debug_write_int(thr, (duk_int32_t) n);
47080 fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun);
47081 for (i = 0; i < n; i++) {
47082 duk_debug_write_hobject(thr, *fn);
47083 fn++;
47084 }
47085 duk_debug_write_string(thr,
47086 (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun),
47087 (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun));
47088 duk_debug_write_eom(thr);
47089 return;
47090
47091 fail_args:
47092 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
47093 return;
47094
47095 fail_index:
47096 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
47097 return;
47098}
47099
47100/*
47101 * Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
47102 * GetObjPropDescRange
47103 */
47104
47105#if defined(DUK_USE_DEBUGGER_INSPECT)
47106
47107#if 0 /* pruned */
47108DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
47109 "reachable",
47110 "temproot",
47111 "finalizable",
47112 "finalized",
47113 "readonly"
47114 /* NULL not needed here */
47115};
47116DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
47117 DUK_HEAPHDR_FLAG_REACHABLE,
47118 DUK_HEAPHDR_FLAG_TEMPROOT,
47119 DUK_HEAPHDR_FLAG_FINALIZABLE,
47120 DUK_HEAPHDR_FLAG_FINALIZED,
47121 DUK_HEAPHDR_FLAG_READONLY,
47122 0 /* terminator */
47123};
47124#endif
47125DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
47126#if 0
47127 "arridx",
47128 "symbol",
47129 "hidden",
47130 "reserved_word",
47131 "strict_reserved_word",
47132 "eval_or_arguments",
47133#endif
47134 "extdata"
47135 /* NULL not needed here */
47136};
47137DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
47138#if 0
47139 DUK_HSTRING_FLAG_ARRIDX,
47140 DUK_HSTRING_FLAG_SYMBOL,
47141 DUK_HSTRING_FLAG_HIDDEN,
47142 DUK_HSTRING_FLAG_RESERVED_WORD,
47143 DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
47144 DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
47145#endif
47146 DUK_HSTRING_FLAG_EXTDATA,
47147 0 /* terminator */
47148};
47149DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
47150 "extensible",
47151 "constructable",
47152 "callable",
47153 "boundfunc",
47154 "compfunc",
47155 "natfunc",
47156 "bufobj",
47157 "fastrefs",
47158 "array_part",
47159 "strict",
47160 "notail",
47161 "newenv",
47162 "namebinding",
47163 "createargs",
47164 "have_finalizer",
47165 "exotic_array",
47166 "exotic_stringobj",
47167 "exotic_arguments",
47168 "exotic_proxyobj",
47169 "special_call"
47170 /* NULL not needed here */
47171};
47172DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
47173 DUK_HOBJECT_FLAG_EXTENSIBLE,
47174 DUK_HOBJECT_FLAG_CONSTRUCTABLE,
47175 DUK_HOBJECT_FLAG_CALLABLE,
47176 DUK_HOBJECT_FLAG_BOUNDFUNC,
47177 DUK_HOBJECT_FLAG_COMPFUNC,
47178 DUK_HOBJECT_FLAG_NATFUNC,
47179 DUK_HOBJECT_FLAG_BUFOBJ,
47180 DUK_HOBJECT_FLAG_FASTREFS,
47181 DUK_HOBJECT_FLAG_ARRAY_PART,
47182 DUK_HOBJECT_FLAG_STRICT,
47183 DUK_HOBJECT_FLAG_NOTAIL,
47184 DUK_HOBJECT_FLAG_NEWENV,
47185 DUK_HOBJECT_FLAG_NAMEBINDING,
47186 DUK_HOBJECT_FLAG_CREATEARGS,
47187 DUK_HOBJECT_FLAG_HAVE_FINALIZER,
47188 DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
47189 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
47190 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
47191 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
47192 DUK_HOBJECT_FLAG_SPECIAL_CALL,
47193 0 /* terminator */
47194};
47195DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
47196 "dynamic",
47197 "external"
47198 /* NULL not needed here */
47199};
47200DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
47201 DUK_HBUFFER_FLAG_DYNAMIC,
47202 DUK_HBUFFER_FLAG_EXTERNAL,
47203 0 /* terminator */
47204};
47205
47206DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
47207 duk_debug_write_uint(thr, 0);
47208 duk_debug_write_cstring(thr, key);
47209}
47210
47211DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
47212 duk_debug_write_uint(thr, 0);
47213 duk_debug_write_cstring(thr, key);
47214 duk_debug_write_uint(thr, val);
47215}
47216
47217DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
47218 duk_debug_write_uint(thr, 0);
47219 duk_debug_write_cstring(thr, key);
47220 duk_debug_write_int(thr, val);
47221}
47222
47223DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
47224 duk_debug_write_uint(thr, 0);
47225 duk_debug_write_cstring(thr, key);
47226 duk_debug_write_boolean(thr, val);
47227}
47228
47229DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
47230 const char *key;
47231 duk_uint_t mask;
47232
47233 for (;;) {
47234 mask = *masks++;
47235 if (mask == 0) {
47236 break;
47237 }
47238 key = *keys++;
47239 DUK_ASSERT(key != NULL);
47240
47241 DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
47242 duk__debug_getinfo_prop_bool(thr, key, flags & mask);
47243 }
47244}
47245
47246/* Inspect a property using a virtual index into a conceptual property list
47247 * consisting of (1) all array part items from [0,a_size[ (even when above
47248 * .length) and (2) all entry part items from [0,e_next[. Unused slots are
47249 * indicated using dvalue 'unused'.
47250 */
47251DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
47252 duk_uint_t a_size;
47253 duk_tval *tv;
47254 duk_hstring *h_key;
47255 duk_hobject *h_getset;
47256 duk_uint_t flags;
47257
47258 DUK_UNREF(heap);
47259
47260 a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
47261 if (idx < a_size) {
47262 duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
47263 duk_debug_write_uint(thr, idx);
47264 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
47265 duk_debug_write_tval(thr, tv);
47266 return 1;
47267 }
47268
47269 idx -= a_size;
47270 if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
47271 return 0;
47272 }
47273
47274 h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
47275 if (h_key == NULL) {
47276 duk_debug_write_uint(thr, 0);
47277 duk_debug_write_null(thr);
47278 duk_debug_write_unused(thr);
47279 return 1;
47280 }
47281
47282 flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
47283 if (DUK_HSTRING_HAS_SYMBOL(h_key)) {
47284 flags |= DUK_DBG_PROPFLAG_SYMBOL;
47285 }
47286 if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
47287 flags |= DUK_DBG_PROPFLAG_HIDDEN;
47288 }
47289 duk_debug_write_uint(thr, flags);
47290 duk_debug_write_hstring(thr, h_key);
47291 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
47292 h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
47293 if (h_getset) {
47294 duk_debug_write_hobject(thr, h_getset);
47295 } else {
47296 duk_debug_write_null(thr);
47297 }
47298 h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
47299 if (h_getset) {
47300 duk_debug_write_hobject(thr, h_getset);
47301 } else {
47302 duk_debug_write_null(thr);
47303 }
47304 } else {
47305 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
47306 duk_debug_write_tval(thr, tv);
47307 }
47308 return 1;
47309}
47310
47311DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
47312 duk_heaphdr *h;
47313
47314 DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
47315 DUK_UNREF(heap);
47316
47317 DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1);
47318 DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1);
47319 DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1);
47320
47321 h = duk_debug_read_any_ptr(thr);
47322 if (!h) {
47323 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
47324 return;
47325 }
47326
47327 duk_debug_write_reply(thr);
47328
47329 /* As with all inspection code, we rely on the debug client providing
47330 * a valid, non-stale pointer: there's no portable way to safely
47331 * validate the pointer here.
47332 */
47333
47334 duk__debug_getinfo_flags_key(thr, "heapptr");
47335 duk_debug_write_heapptr(thr, h);
47336
47337 /* XXX: comes out as signed now */
47338 duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
47339 duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
47340#if defined(DUK_USE_REFERENCE_COUNTING)
47341 duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
47342#endif
47343#if 0 /* pruned */
47344 duk__debug_getinfo_bitmask(thr,
47345 duk__debug_getinfo_heaphdr_keys,
47346 duk__debug_getinfo_heaphdr_masks,
47347 DUK_HEAPHDR_GET_FLAGS_RAW(h));
47348#endif
47349
47350 switch (DUK_HEAPHDR_GET_TYPE(h)) {
47351 case DUK_HTYPE_STRING: {
47352 duk_hstring *h_str;
47353
47354 h_str = (duk_hstring *) h;
47355 duk__debug_getinfo_bitmask(thr,
47356 duk__debug_getinfo_hstring_keys,
47357 duk__debug_getinfo_hstring_masks,
47358 DUK_HEAPHDR_GET_FLAGS_RAW(h));
47359 duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str));
47360 duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str));
47361 duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str));
47362 duk__debug_getinfo_flags_key(thr, "data");
47363 duk_debug_write_hstring(thr, h_str);
47364 break;
47365 }
47366 case DUK_HTYPE_OBJECT: {
47367 duk_hobject *h_obj;
47368 duk_hobject *h_proto;
47369
47370 h_obj = (duk_hobject *) h;
47371 h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
47372
47373 /* duk_hobject specific fields. */
47374 duk__debug_getinfo_bitmask(thr,
47375 duk__debug_getinfo_hobject_keys,
47376 duk__debug_getinfo_hobject_masks,
47377 DUK_HEAPHDR_GET_FLAGS_RAW(h));
47378 duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
47379 duk__debug_getinfo_flags_key(thr, "class_name");
47380 duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
47381 duk__debug_getinfo_flags_key(thr, "prototype");
47382 if (h_proto != NULL) {
47383 duk_debug_write_hobject(thr, h_proto);
47384 } else {
47385 duk_debug_write_null(thr);
47386 }
47387 duk__debug_getinfo_flags_key(thr, "props");
47388 duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
47389 duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
47390 duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
47391 duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
47392 duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
47393
47394 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
47395 duk_harray *h_arr;
47396 h_arr = (duk_harray *) h_obj;
47397
47398 duk__debug_getinfo_prop_uint(thr, "length", (duk_uint_t) h_arr->length);
47399 duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable);
47400 }
47401
47402 if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
47403 duk_hnatfunc *h_fun;
47404 h_fun = (duk_hnatfunc *) h_obj;
47405
47406 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
47407 duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
47408 duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS);
47409 /* Native function pointer may be different from a void pointer,
47410 * and we serialize it from memory directly now (no byte swapping etc).
47411 */
47412 duk__debug_getinfo_flags_key(thr, "funcptr");
47413 duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
47414 }
47415
47416 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
47417 duk_hcompfunc *h_fun;
47418 duk_hbuffer *h_buf;
47419 duk_hobject *h_lexenv;
47420 duk_hobject *h_varenv;
47421 h_fun = (duk_hcompfunc *) h_obj;
47422
47423 duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
47424 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
47425
47426 duk__debug_getinfo_flags_key(thr, "lex_env");
47427 h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun);
47428 if (h_lexenv != NULL) {
47429 duk_debug_write_hobject(thr, h_lexenv);
47430 } else {
47431 duk_debug_write_null(thr);
47432 }
47433 duk__debug_getinfo_flags_key(thr, "var_env");
47434 h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun);
47435 if (h_varenv != NULL) {
47436 duk_debug_write_hobject(thr, h_varenv);
47437 } else {
47438 duk_debug_write_null(thr);
47439 }
47440
47441 duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
47442 duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
47443 h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun);
47444 if (h_buf != NULL) {
47445 duk__debug_getinfo_flags_key(thr, "data");
47446 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
47447 }
47448 }
47449
47450 if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
47451 duk_hboundfunc *h_bfun;
47452 h_bfun = (duk_hboundfunc *) (void *) h_obj;
47453
47454 duk__debug_getinfo_flags_key(thr, "target");
47455 duk_debug_write_tval(thr, &h_bfun->target);
47456 duk__debug_getinfo_flags_key(thr, "this_binding");
47457 duk_debug_write_tval(thr, &h_bfun->this_binding);
47458 duk__debug_getinfo_flags_key(thr, "nargs");
47459 duk_debug_write_int(thr, h_bfun->nargs);
47460 /* h_bfun->args not exposed now */
47461 }
47462
47463 if (DUK_HOBJECT_IS_THREAD(h_obj)) {
47464 /* XXX: Currently no inspection of threads, e.g. value stack, call
47465 * stack, catch stack, etc.
47466 */
47467 duk_hthread *h_thr;
47468 h_thr = (duk_hthread *) h_obj;
47469 DUK_UNREF(h_thr);
47470 }
47471
47472 if (DUK_HOBJECT_IS_DECENV(h_obj)) {
47473 duk_hdecenv *h_env;
47474 h_env = (duk_hdecenv *) h_obj;
47475
47476 duk__debug_getinfo_flags_key(thr, "thread");
47477 duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread));
47478 duk__debug_getinfo_flags_key(thr, "varmap");
47479 duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap));
47480 duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase_byteoff);
47481 }
47482
47483 if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
47484 duk_hobjenv *h_env;
47485 h_env = (duk_hobjenv *) h_obj;
47486
47487 duk__debug_getinfo_flags_key(thr, "target");
47488 duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target));
47489 duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this);
47490 }
47491
47492#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
47493 if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
47494 duk_hbufobj *h_bufobj;
47495 h_bufobj = (duk_hbufobj *) h_obj;
47496
47497 duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
47498 duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
47499 duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
47500 duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
47501 duk__debug_getinfo_prop_bool(thr, "is_typedarray", (duk_uint_t) h_bufobj->is_typedarray);
47502 if (h_bufobj->buf != NULL) {
47503 duk__debug_getinfo_flags_key(thr, "buffer");
47504 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
47505 }
47506 }
47507#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
47508 break;
47509 }
47510 case DUK_HTYPE_BUFFER: {
47511 duk_hbuffer *h_buf;
47512
47513 h_buf = (duk_hbuffer *) h;
47514 duk__debug_getinfo_bitmask(thr,
47515 duk__debug_getinfo_hbuffer_keys,
47516 duk__debug_getinfo_hbuffer_masks,
47517 DUK_HEAPHDR_GET_FLAGS_RAW(h));
47518 duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
47519 duk__debug_getinfo_flags_key(thr, "dataptr");
47520 duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
47521 duk__debug_getinfo_flags_key(thr, "data");
47522 duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */
47523 break;
47524 }
47525 default: {
47526 /* Since we already started writing the reply, just emit nothing. */
47527 DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
47528 }
47529 }
47530
47531 duk_debug_write_eom(thr);
47532}
47533
47534DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
47535 duk_heaphdr *h;
47536 duk_hobject *h_obj;
47537 duk_hstring *h_key;
47538 duk_propdesc desc;
47539
47540 DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
47541 DUK_UNREF(heap);
47542
47543 h = duk_debug_read_any_ptr(thr);
47544 if (!h) {
47545 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
47546 return;
47547 }
47548 h_key = duk_debug_read_hstring(thr);
47549 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
47550 goto fail_args;
47551 }
47552 h_obj = (duk_hobject *) h;
47553
47554 if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
47555 duk_int_t virtual_idx;
47556 duk_bool_t rc;
47557
47558 /* To use the shared helper need the virtual index. */
47559 DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
47560 virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
47561 (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
47562
47563 duk_debug_write_reply(thr);
47564 rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
47565 DUK_ASSERT(rc == 1);
47566 DUK_UNREF(rc);
47567 duk_debug_write_eom(thr);
47568 } else {
47569 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
47570 }
47571 return;
47572
47573 fail_args:
47574 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
47575}
47576
47577DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
47578 duk_heaphdr *h;
47579 duk_hobject *h_obj;
47580 duk_uint_t idx, idx_start, idx_end;
47581
47582 DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
47583 DUK_UNREF(heap);
47584
47585 h = duk_debug_read_any_ptr(thr);
47586 idx_start = (duk_uint_t) duk_debug_read_int(thr);
47587 idx_end = (duk_uint_t) duk_debug_read_int(thr);
47588 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
47589 goto fail_args;
47590 }
47591 h_obj = (duk_hobject *) h;
47592
47593 /* The index range space is conceptually the array part followed by the
47594 * entry part. Unlike normal enumeration all slots are exposed here as
47595 * is and return 'unused' if the slots are not in active use. In particular
47596 * the array part is included for the full a_size regardless of what the
47597 * array .length is.
47598 */
47599
47600 duk_debug_write_reply(thr);
47601 for (idx = idx_start; idx < idx_end; idx++) {
47602 if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
47603 break;
47604 }
47605 }
47606 duk_debug_write_eom(thr);
47607 return;
47608
47609 fail_args:
47610 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
47611}
47612
47613#endif /* DUK_USE_DEBUGGER_INSPECT */
47614
47615/*
47616 * Process incoming debug requests
47617 *
47618 * Individual request handlers can push temporaries on the value stack and
47619 * rely on duk__debug_process_message() to restore the value stack top
47620 * automatically.
47621 */
47622
47623/* Process one debug message. Automatically restore value stack top to its
47624 * entry value, so that individual message handlers don't need exact value
47625 * stack handling which is convenient.
47626 */
47627DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
47628 duk_heap *heap;
47629 duk_uint8_t x;
47630 duk_int32_t cmd;
47631 duk_idx_t entry_top;
47632
47633 DUK_ASSERT(thr != NULL);
47634 heap = thr->heap;
47635 DUK_ASSERT(heap != NULL);
47636
47637 entry_top = duk_get_top(thr);
47638
47639 x = duk_debug_read_byte(thr);
47640 switch (x) {
47641 case DUK_DBG_IB_REQUEST: {
47642 cmd = duk_debug_read_int(thr);
47643 switch (cmd) {
47644 case DUK_DBG_CMD_BASICINFO: {
47645 duk__debug_handle_basic_info(thr, heap);
47646 break;
47647 }
47648 case DUK_DBG_CMD_TRIGGERSTATUS: {
47649 duk__debug_handle_trigger_status(thr, heap);
47650 break;
47651 }
47652 case DUK_DBG_CMD_PAUSE: {
47653 duk__debug_handle_pause(thr, heap);
47654 break;
47655 }
47656 case DUK_DBG_CMD_RESUME: {
47657 duk__debug_handle_resume(thr, heap);
47658 break;
47659 }
47660 case DUK_DBG_CMD_STEPINTO:
47661 case DUK_DBG_CMD_STEPOVER:
47662 case DUK_DBG_CMD_STEPOUT: {
47663 duk__debug_handle_step(thr, heap, cmd);
47664 break;
47665 }
47666 case DUK_DBG_CMD_LISTBREAK: {
47667 duk__debug_handle_list_break(thr, heap);
47668 break;
47669 }
47670 case DUK_DBG_CMD_ADDBREAK: {
47671 duk__debug_handle_add_break(thr, heap);
47672 break;
47673 }
47674 case DUK_DBG_CMD_DELBREAK: {
47675 duk__debug_handle_del_break(thr, heap);
47676 break;
47677 }
47678 case DUK_DBG_CMD_GETVAR: {
47679 duk__debug_handle_get_var(thr, heap);
47680 break;
47681 }
47682 case DUK_DBG_CMD_PUTVAR: {
47683 duk__debug_handle_put_var(thr, heap);
47684 break;
47685 }
47686 case DUK_DBG_CMD_GETCALLSTACK: {
47687 duk__debug_handle_get_call_stack(thr, heap);
47688 break;
47689 }
47690 case DUK_DBG_CMD_GETLOCALS: {
47691 duk__debug_handle_get_locals(thr, heap);
47692 break;
47693 }
47694 case DUK_DBG_CMD_EVAL: {
47695 duk__debug_handle_eval(thr, heap);
47696 break;
47697 }
47698 case DUK_DBG_CMD_DETACH: {
47699 /* The actual detached_cb call is postponed to message loop so
47700 * we don't need any special precautions here (just skip to EOM
47701 * on the already closed connection).
47702 */
47703 duk__debug_handle_detach(thr, heap);
47704 break;
47705 }
47706#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
47707 case DUK_DBG_CMD_DUMPHEAP: {
47708 duk__debug_handle_dump_heap(thr, heap);
47709 break;
47710 }
47711#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
47712 case DUK_DBG_CMD_GETBYTECODE: {
47713 duk__debug_handle_get_bytecode(thr, heap);
47714 break;
47715 }
47716 case DUK_DBG_CMD_APPREQUEST: {
47717 duk__debug_handle_apprequest(thr, heap);
47718 break;
47719 }
47720#if defined(DUK_USE_DEBUGGER_INSPECT)
47721 case DUK_DBG_CMD_GETHEAPOBJINFO: {
47722 duk__debug_handle_get_heap_obj_info(thr, heap);
47723 break;
47724 }
47725 case DUK_DBG_CMD_GETOBJPROPDESC: {
47726 duk__debug_handle_get_obj_prop_desc(thr, heap);
47727 break;
47728 }
47729 case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
47730 duk__debug_handle_get_obj_prop_desc_range(thr, heap);
47731 break;
47732 }
47733#endif /* DUK_USE_DEBUGGER_INSPECT */
47734 default: {
47735 DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
47736 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
47737 }
47738 } /* switch cmd */
47739 break;
47740 }
47741 case DUK_DBG_IB_REPLY: {
47742 DUK_D(DUK_DPRINT("debug reply, skipping"));
47743 break;
47744 }
47745 case DUK_DBG_IB_ERROR: {
47746 DUK_D(DUK_DPRINT("debug error, skipping"));
47747 break;
47748 }
47749 case DUK_DBG_IB_NOTIFY: {
47750 DUK_D(DUK_DPRINT("debug notify, skipping"));
47751 break;
47752 }
47753 default: {
47754 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
47755 goto fail;
47756 }
47757 } /* switch initial byte */
47758
47759 DUK_ASSERT(duk_get_top(thr) >= entry_top);
47760 duk_set_top(thr, entry_top);
47761 duk__debug_skip_to_eom(thr);
47762 return;
47763
47764 fail:
47765 DUK_ASSERT(duk_get_top(thr) >= entry_top);
47766 duk_set_top(thr, entry_top);
47767 DUK__SET_CONN_BROKEN(thr, 1);
47768 return;
47769}
47770
47771DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
47772 if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
47773 duk_debug_send_status(thr);
47774 thr->heap->dbg_state_dirty = 0;
47775 }
47776}
47777
47778DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
47779#if defined(DUK_USE_ASSERTIONS)
47780 duk_idx_t entry_top;
47781#endif
47782 duk_bool_t retval = 0;
47783
47784 DUK_ASSERT(thr != NULL);
47785 DUK_ASSERT(thr->heap != NULL);
47786#if defined(DUK_USE_ASSERTIONS)
47787 entry_top = duk_get_top(thr);
47788#endif
47789
47790 DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
47791 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
47792 (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
47793 DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(thr)));
47794
47795 /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
47796 * the message loop caused a transport error and detach1() to run.
47797 */
47798 DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
47799 DUK_ASSERT(thr->heap->dbg_processing == 0);
47800 thr->heap->dbg_processing = 1;
47801
47802 /* Ensure dirty state causes a Status even if never process any
47803 * messages. This is expected by the bytecode executor when in
47804 * the running state.
47805 */
47806 duk__check_resend_status(thr);
47807
47808 for (;;) {
47809 /* Process messages until we're no longer paused or we peek
47810 * and see there's nothing to read right now.
47811 */
47812 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(thr)));
47813 DUK_ASSERT(thr->heap->dbg_processing == 1);
47814
47815 while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
47816 /* Detach is pending; can be triggered from outside the
47817 * debugger loop (e.g. Status notify write error) or by
47818 * previous message handling. Call detached callback
47819 * here, in a controlled state, to ensure a possible
47820 * reattach inside the detached_cb is handled correctly.
47821 *
47822 * Recheck for detach in a while loop: an immediate
47823 * reattach involves a call to duk_debugger_attach()
47824 * which writes a debugger handshake line immediately
47825 * inside the API call. If the transport write fails
47826 * for that handshake, we can immediately end up in a
47827 * "transport broken, detaching" case several times here.
47828 * Loop back until we're either cleanly attached or
47829 * fully detached.
47830 *
47831 * NOTE: Reset dbg_processing = 1 forcibly, in case we
47832 * re-attached; duk_debugger_attach() sets dbg_processing
47833 * to 0 at the moment.
47834 */
47835
47836 DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
47837
47838 duk__debug_do_detach2(thr->heap);
47839 thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */
47840
47841 DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
47842 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
47843 }
47844 DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */
47845 DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */
47846
47847 if (thr->heap->dbg_read_cb == NULL) {
47848 DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
47849 break;
47850 }
47851
47852 if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) {
47853 if (!duk_debug_read_peek(thr)) {
47854 /* Note: peek cannot currently trigger a detach
47855 * so the dbg_detaching == 0 assert outside the
47856 * loop is correct.
47857 */
47858 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
47859 break;
47860 }
47861 DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
47862 } else {
47863 DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
47864 }
47865
47866 duk__check_resend_status(thr);
47867 duk__debug_process_message(thr);
47868 duk__check_resend_status(thr);
47869
47870 retval = 1; /* processed one or more messages */
47871 }
47872
47873 DUK_ASSERT(thr->heap->dbg_detaching == 0);
47874 DUK_ASSERT(thr->heap->dbg_processing == 1);
47875 thr->heap->dbg_processing = 0;
47876
47877 /* As an initial implementation, read flush after exiting the message
47878 * loop. If transport is broken, this is a no-op (with debug logs).
47879 */
47880 duk_debug_read_flush(thr); /* this cannot initiate a detach */
47881 DUK_ASSERT(thr->heap->dbg_detaching == 0);
47882
47883 DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(thr)));
47884
47885#if defined(DUK_USE_ASSERTIONS)
47886 /* Easy to get wrong, so assert for it. */
47887 DUK_ASSERT(entry_top == duk_get_top(thr));
47888#endif
47889
47890 return retval;
47891}
47892
47893/*
47894 * Halt execution helper
47895 */
47896
47897/* Halt execution and enter a debugger message loop until execution is resumed
47898 * by the client. PC for the current activation may be temporarily decremented
47899 * so that the "current" instruction will be shown by the client. This helper
47900 * is callable from anywhere, also outside bytecode executor.
47901 */
47902
47903DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
47904 duk_activation *act;
47905 duk_hcompfunc *fun;
47906 duk_instr_t *old_pc = NULL;
47907
47908 DUK_ASSERT(thr != NULL);
47909 DUK_ASSERT(thr->heap != NULL);
47910 DUK_ASSERT(duk_debug_is_attached(thr->heap));
47911 DUK_ASSERT(thr->heap->dbg_processing == 0);
47912 DUK_ASSERT(!duk_debug_is_paused(thr->heap));
47913
47914 duk_debug_set_paused(thr->heap);
47915
47916 act = thr->callstack_curr;
47917
47918 /* NOTE: act may be NULL if an error is thrown outside of any activation,
47919 * which may happen in the case of, e.g. syntax errors.
47920 */
47921
47922 /* Decrement PC if that was requested, this requires a PC sync. */
47923 if (act != NULL) {
47924 duk_hthread_sync_currpc(thr);
47925 old_pc = act->curr_pc;
47926 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
47927
47928 /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
47929 * guaranteed to be a non-NULL ECMAScript function.
47930 */
47931 DUK_ASSERT(act->curr_pc == NULL ||
47932 (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)));
47933 if (use_prev_pc &&
47934 act->curr_pc != NULL &&
47935 act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) {
47936 act->curr_pc--;
47937 }
47938 }
47939
47940 /* Process debug messages until we are no longer paused. */
47941
47942 /* NOTE: This is a bit fragile. It's important to ensure that
47943 * duk_debug_process_messages() never throws an error or
47944 * act->curr_pc will never be reset.
47945 */
47946
47947 thr->heap->dbg_state_dirty = 1;
47948 while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
47949 DUK_ASSERT(duk_debug_is_attached(thr->heap));
47950 DUK_ASSERT(thr->heap->dbg_processing == 0);
47951 duk_debug_process_messages(thr, 0 /*no_block*/);
47952 }
47953
47954 /* XXX: Decrementing and restoring act->curr_pc works now, but if the
47955 * debugger message loop gains the ability to adjust the current PC
47956 * (e.g. a forced jump) restoring the PC here will break. Another
47957 * approach would be to use a state flag for the "decrement 1 from
47958 * topmost activation's PC" and take it into account whenever dealing
47959 * with PC values.
47960 */
47961 if (act != NULL) {
47962 act->curr_pc = old_pc; /* restore PC */
47963 }
47964}
47965
47966/*
47967 * Breakpoint management
47968 */
47969
47970DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
47971 duk_heap *heap;
47972 duk_breakpoint *b;
47973
47974 /* Caller must trigger recomputation of active breakpoint list. To
47975 * ensure stale values are not used if that doesn't happen, clear the
47976 * active breakpoint list here.
47977 */
47978
47979 DUK_ASSERT(thr != NULL);
47980 DUK_ASSERT(filename != NULL);
47981 heap = thr->heap;
47982 DUK_ASSERT(heap != NULL);
47983
47984 if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
47985 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
47986 (duk_heaphdr *) filename, (long) line));
47987 return -1;
47988 }
47989 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
47990 b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
47991 b->filename = filename;
47992 b->line = line;
47993 DUK_HSTRING_INCREF(thr, filename);
47994
47995 return (duk_small_int_t) (heap->dbg_breakpoint_count - 1); /* index */
47996}
47997
47998DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
47999 duk_heap *heap;
48000 duk_hstring *h;
48001 duk_breakpoint *b;
48002 duk_size_t move_size;
48003
48004 /* Caller must trigger recomputation of active breakpoint list. To
48005 * ensure stale values are not used if that doesn't happen, clear the
48006 * active breakpoint list here.
48007 */
48008
48009 DUK_ASSERT(thr != NULL);
48010 heap = thr->heap;
48011 DUK_ASSERT(heap != NULL);
48012 DUK_ASSERT(duk_debug_is_attached(thr->heap));
48013 DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
48014
48015 if (breakpoint_index >= heap->dbg_breakpoint_count) {
48016 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
48017 return 0;
48018 }
48019 b = heap->dbg_breakpoints + breakpoint_index;
48020
48021 h = b->filename;
48022 DUK_ASSERT(h != NULL);
48023
48024 move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
48025 duk_memmove((void *) b,
48026 (const void *) (b + 1),
48027 (size_t) move_size);
48028
48029 heap->dbg_breakpoint_count--;
48030 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
48031
48032 DUK_HSTRING_DECREF(thr, h); /* side effects */
48033 DUK_UNREF(h); /* w/o refcounting */
48034
48035 /* Breakpoint entries above the used area are left as garbage. */
48036
48037 return 1;
48038}
48039
48040/*
48041 * Misc state management
48042 */
48043
48044DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) {
48045 return (heap->dbg_read_cb != NULL);
48046}
48047
48048DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) {
48049 return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0);
48050}
48051
48052DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) {
48053 if (duk_debug_is_paused(heap)) {
48054 DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring"));
48055 } else {
48056 DUK_HEAP_SET_DEBUGGER_PAUSED(heap);
48057 heap->dbg_state_dirty = 1;
48058 duk_debug_clear_pause_state(heap);
48059 DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */
48060 heap->ms_running = 2; /* prevent mark-and-sweep, prevent refzero queueing */
48061 heap->ms_prevent_count++;
48062 DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */
48063 DUK_ASSERT(heap->heap_thread != NULL);
48064 }
48065}
48066
48067DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) {
48068 if (duk_debug_is_paused(heap)) {
48069 DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
48070 heap->dbg_state_dirty = 1;
48071 duk_debug_clear_pause_state(heap);
48072 DUK_ASSERT(heap->ms_running == 2);
48073 DUK_ASSERT(heap->ms_prevent_count > 0);
48074 heap->ms_prevent_count--;
48075 heap->ms_running = 0;
48076 DUK_ASSERT(heap->heap_thread != NULL);
48077 } else {
48078 DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring"));
48079 }
48080}
48081
48082DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) {
48083 heap->dbg_pause_flags = 0;
48084 heap->dbg_pause_act = NULL;
48085 heap->dbg_pause_startline = 0;
48086}
48087
48088#else /* DUK_USE_DEBUGGER_SUPPORT */
48089
48090/* No debugger support. */
48091
48092#endif /* DUK_USE_DEBUGGER_SUPPORT */
48093
48094/* automatic undefs */
48095#undef DUK__DBG_TPORT_ENTER
48096#undef DUK__DBG_TPORT_EXIT
48097#undef DUK__SET_CONN_BROKEN
48098#line 1 "duk_error_augment.c"
48099/*
48100 * Augmenting errors at their creation site and their throw site.
48101 *
48102 * When errors are created, traceback data is added by built-in code
48103 * and a user error handler (if defined) can process or replace the
48104 * error. Similarly, when errors are thrown, a user error handler
48105 * (if defined) can process or replace the error.
48106 *
48107 * Augmentation and other processing at error creation time is nice
48108 * because an error is only created once, but it may be thrown and
48109 * rethrown multiple times. User error handler registered for processing
48110 * an error at its throw site must be careful to handle rethrowing in
48111 * a useful manner.
48112 *
48113 * Error augmentation may throw an internal error (e.g. alloc error).
48114 *
48115 * ECMAScript allows throwing any values, so all values cannot be
48116 * augmented. Currently, the built-in augmentation at error creation
48117 * only augments error values which are Error instances (= have the
48118 * built-in Error.prototype in their prototype chain) and are also
48119 * extensible. User error handlers have no limitations in this respect.
48120 */
48121
48122/* #include duk_internal.h -> already included */
48123
48124/*
48125 * Helper for calling a user error handler.
48126 *
48127 * 'thr' must be the currently active thread; the error handler is called
48128 * in its context. The valstack of 'thr' must have the error value on
48129 * top, and will be replaced by another error value based on the return
48130 * value of the error handler.
48131 *
48132 * The helper calls duk_handle_call() recursively in protected mode.
48133 * Before that call happens, no longjmps should happen; as a consequence,
48134 * we must assume that the valstack contains enough temporary space for
48135 * arguments and such.
48136 *
48137 * While the error handler runs, any errors thrown will not trigger a
48138 * recursive error handler call (this is implemented using a heap level
48139 * flag which will "follow" through any coroutines resumed inside the
48140 * error handler). If the error handler is not callable or throws an
48141 * error, the resulting error replaces the original error (for Duktape
48142 * internal errors, duk_error_throw.c further substitutes this error with
48143 * a DoubleError which is not ideal). This would be easy to change and
48144 * even signal to the caller.
48145 *
48146 * The user error handler is stored in 'Duktape.errCreate' or
48147 * 'Duktape.errThrow' depending on whether we're augmenting the error at
48148 * creation or throw time. There are several alternatives to this approach,
48149 * see doc/error-objects.rst for discussion.
48150 *
48151 * Note: since further longjmp()s may occur while calling the error handler
48152 * (for many reasons, e.g. a labeled 'break' inside the handler), the
48153 * caller can make no assumptions on the thr->heap->lj state after the
48154 * call (this affects especially duk_error_throw.c). This is not an issue
48155 * as long as the caller writes to the lj state only after the error handler
48156 * finishes.
48157 */
48158
48159#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
48160DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
48161 duk_tval *tv_hnd;
48162 duk_int_t rc;
48163
48164 DUK_ASSERT(thr != NULL);
48165 DUK_ASSERT(thr->heap != NULL);
48166 DUK_ASSERT_STRIDX_VALID(stridx_cb);
48167
48168 if (thr->heap->augmenting_error) {
48169 DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore"));
48170 return;
48171 }
48172
48173 /*
48174 * Check whether or not we have an error handler.
48175 *
48176 * We must be careful of not triggering an error when looking up the
48177 * property. For instance, if the property is a getter, we don't want
48178 * to call it, only plain values are allowed. The value, if it exists,
48179 * is not checked. If the value is not a function, a TypeError happens
48180 * when it is called and that error replaces the original one.
48181 */
48182
48183 DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
48184
48185 /* [ ... errval ] */
48186
48187 if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
48188 /* When creating built-ins, some of the built-ins may not be set
48189 * and we want to tolerate that when throwing errors.
48190 */
48191 DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
48192 return;
48193 }
48194 tv_hnd = duk_hobject_find_entry_tval_ptr_stridx(thr->heap,
48195 thr->builtins[DUK_BIDX_DUKTAPE],
48196 stridx_cb);
48197 if (tv_hnd == NULL) {
48198 DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
48199 (duk_tval *) tv_hnd));
48200 return;
48201 }
48202 DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
48203 (duk_tval *) tv_hnd));
48204 duk_push_tval(thr, tv_hnd);
48205
48206 /* [ ... errval errhandler ] */
48207
48208 duk_insert(thr, -2); /* -> [ ... errhandler errval ] */
48209 duk_push_undefined(thr);
48210 duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */
48211
48212 /* [ ... errhandler undefined errval ] */
48213
48214 /*
48215 * heap->augmenting_error prevents recursive re-entry and also causes
48216 * call handling to use a larger (but not unbounded) call stack limit
48217 * for the duration of error augmentation.
48218 *
48219 * We ignore errors now: a success return and an error value both
48220 * replace the original error value. (This would be easy to change.)
48221 */
48222
48223 DUK_ASSERT(thr->heap->augmenting_error == 0);
48224 thr->heap->augmenting_error = 1;
48225
48226 rc = duk_pcall_method(thr, 1);
48227 DUK_UNREF(rc); /* no need to check now: both success and error are OK */
48228
48229 DUK_ASSERT(thr->heap->augmenting_error == 1);
48230 thr->heap->augmenting_error = 0;
48231
48232 /* [ ... errval ] */
48233}
48234#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
48235
48236/*
48237 * Add ._Tracedata to an error on the stack top.
48238 */
48239
48240#if defined(DUK_USE_TRACEBACKS)
48241DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
48242 duk_activation *act;
48243 duk_int_t depth;
48244 duk_int_t arr_size;
48245 duk_tval *tv;
48246 duk_hstring *s;
48247 duk_uint32_t u32;
48248 duk_double_t d;
48249
48250 DUK_ASSERT(thr != NULL);
48251 DUK_ASSERT(thr_callstack != NULL);
48252
48253 /* [ ... error ] */
48254
48255 /*
48256 * The traceback format is pretty arcane in an attempt to keep it compact
48257 * and cheap to create. It may change arbitrarily from version to version.
48258 * It should be decoded/accessed through version specific accessors only.
48259 *
48260 * See doc/error-objects.rst.
48261 */
48262
48263 DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
48264 (duk_tval *) duk_get_tval(thr, -1)));
48265
48266 /* Preallocate array to correct size, so that we can just write out
48267 * the _Tracedata values into the array part.
48268 */
48269 act = thr->callstack_curr;
48270 depth = DUK_USE_TRACEBACK_DEPTH;
48271 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
48272 if (depth > (duk_int_t) thr_callstack->callstack_top) {
48273 depth = (duk_int_t) thr_callstack->callstack_top;
48274 }
48275 if (depth > 0) {
48276 if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) {
48277 DUK_ASSERT(act != NULL);
48278 act = act->parent;
48279 depth--;
48280 }
48281 }
48282 arr_size = depth * 2;
48283 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
48284 arr_size += 2;
48285 }
48286 if (c_filename) {
48287 /* We need the C filename to be interned before getting the
48288 * array part pointer to avoid any GC interference while the
48289 * array part is populated.
48290 */
48291 duk_push_string(thr, c_filename);
48292 arr_size += 2;
48293 }
48294
48295 /* XXX: Uninitialized would be OK. Maybe add internal primitive to
48296 * push bare duk_harray with size?
48297 */
48298 DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
48299 tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size);
48300 duk_clear_prototype(thr, -1);
48301 DUK_ASSERT(duk_is_bare_object(thr, -1));
48302 DUK_ASSERT(arr_size == 0 || tv != NULL);
48303
48304 /* Compiler SyntaxErrors (and other errors) come first, and are
48305 * blamed by default (not flagged "noblame").
48306 */
48307 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
48308 s = thr->compile_ctx->h_filename;
48309 DUK_TVAL_SET_STRING(tv, s);
48310 DUK_HSTRING_INCREF(thr, s);
48311 tv++;
48312
48313 u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */
48314 DUK_TVAL_SET_U32(tv, u32);
48315 tv++;
48316 }
48317
48318 /* Filename/line from C macros (__FILE__, __LINE__) are added as an
48319 * entry with a special format: (string, number). The number contains
48320 * the line and flags.
48321 */
48322
48323 /* [ ... error c_filename? arr ] */
48324
48325 if (c_filename) {
48326 DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
48327 s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */
48328 DUK_ASSERT(s != NULL);
48329 DUK_TVAL_SET_STRING(tv, s);
48330 DUK_HSTRING_INCREF(thr, s);
48331 tv++;
48332
48333 d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
48334 (duk_double_t) c_line;
48335 DUK_TVAL_SET_DOUBLE(tv, d);
48336 tv++;
48337 }
48338
48339 /* Traceback depth doesn't take into account the filename/line
48340 * special handling above (intentional).
48341 */
48342 for (; depth-- > 0; act = act->parent) {
48343 duk_uint32_t pc;
48344 duk_tval *tv_src;
48345
48346 /* [... arr] */
48347
48348 DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */
48349 DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */
48350
48351 /* Add function object. */
48352 tv_src = &act->tv_func; /* object (function) or lightfunc */
48353 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
48354 DUK_TVAL_SET_TVAL(tv, tv_src);
48355 DUK_TVAL_INCREF(thr, tv);
48356 tv++;
48357
48358 /* Add a number containing: pc, activation flags.
48359 *
48360 * PC points to next instruction, find offending PC. Note that
48361 * PC == 0 for native code.
48362 */
48363 pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act);
48364 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
48365 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
48366 d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
48367 DUK_TVAL_SET_DOUBLE(tv, d);
48368 tv++;
48369 }
48370
48371#if defined(DUK_USE_ASSERTIONS)
48372 {
48373 duk_harray *a;
48374 a = (duk_harray *) duk_known_hobject(thr, -1);
48375 DUK_ASSERT(a != NULL);
48376 DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
48377 DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
48378 DUK_ASSERT(duk_is_bare_object(thr, -1));
48379 }
48380#endif
48381
48382 /* [ ... error c_filename? arr ] */
48383
48384 if (c_filename) {
48385 duk_remove_m2(thr);
48386 }
48387
48388 /* [ ... error arr ] */
48389
48390 duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
48391}
48392#endif /* DUK_USE_TRACEBACKS */
48393
48394/*
48395 * Add .fileName and .lineNumber to an error on the stack top.
48396 */
48397
48398#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS)
48399DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
48400#if defined(DUK_USE_ASSERTIONS)
48401 duk_int_t entry_top;
48402#endif
48403
48404#if defined(DUK_USE_ASSERTIONS)
48405 entry_top = duk_get_top(thr);
48406#endif
48407
48408 /*
48409 * If tracebacks are disabled, 'fileName' and 'lineNumber' are added
48410 * as plain own properties. Since Error.prototype has accessors of
48411 * the same name, we need to define own properties directly (cannot
48412 * just use e.g. duk_put_prop_stridx). Existing properties are not
48413 * overwritten in case they already exist.
48414 */
48415
48416 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
48417 /* Compiler SyntaxError (or other error) gets the primary blame.
48418 * Currently no flag to prevent blaming.
48419 */
48420 duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
48421 duk_push_hstring(thr, thr->compile_ctx->h_filename);
48422 } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) {
48423 /* C call site gets blamed next, unless flagged not to do so.
48424 * XXX: file/line is disabled in minimal builds, so disable this
48425 * too when appropriate.
48426 */
48427 duk_push_int(thr, c_line);
48428 duk_push_string(thr, c_filename);
48429 } else {
48430 /* Finally, blame the innermost callstack entry which has a
48431 * .fileName property.
48432 */
48433 duk_small_uint_t depth;
48434 duk_uint32_t ecma_line;
48435 duk_activation *act;
48436
48437 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
48438 depth = DUK_USE_TRACEBACK_DEPTH;
48439 if (depth > thr_callstack->callstack_top) {
48440 depth = thr_callstack->callstack_top;
48441 }
48442 for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) {
48443 duk_hobject *func;
48444 duk_uint32_t pc;
48445
48446 DUK_ASSERT(act != NULL);
48447 func = DUK_ACT_GET_FUNC(act);
48448 if (func == NULL) {
48449 /* Lightfunc, not blamed now. */
48450 continue;
48451 }
48452
48453 /* PC points to next instruction, find offending PC,
48454 * PC == 0 for native code.
48455 */
48456 pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
48457 DUK_UNREF(pc);
48458 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
48459 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
48460
48461 duk_push_hobject(thr, func);
48462
48463 /* [ ... error func ] */
48464
48465 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
48466 if (!duk_is_string_notsymbol(thr, -1)) {
48467 duk_pop_2(thr);
48468 continue;
48469 }
48470
48471 /* [ ... error func fileName ] */
48472
48473 ecma_line = 0;
48474#if defined(DUK_USE_PC2LINE)
48475 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
48476 ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc);
48477 } else {
48478 /* Native function, no relevant lineNumber. */
48479 }
48480#endif /* DUK_USE_PC2LINE */
48481 duk_push_u32(thr, ecma_line);
48482
48483 /* [ ... error func fileName lineNumber ] */
48484
48485 duk_replace(thr, -3);
48486
48487 /* [ ... error lineNumber fileName ] */
48488 goto define_props;
48489 }
48490
48491 /* No activation matches, use undefined for both .fileName and
48492 * .lineNumber (matches what we do with a _Tracedata based
48493 * no-match lookup.
48494 */
48495 duk_push_undefined(thr);
48496 duk_push_undefined(thr);
48497 }
48498
48499 define_props:
48500 /* [ ... error lineNumber fileName ] */
48501#if defined(DUK_USE_ASSERTIONS)
48502 DUK_ASSERT(duk_get_top(thr) == entry_top + 2);
48503#endif
48504 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
48505 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
48506}
48507#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
48508
48509/*
48510 * Add line number to a compiler error.
48511 */
48512
48513#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
48514DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
48515
48516 /* Append a "(line NNN)" to the "message" property of any error
48517 * thrown during compilation. Usually compilation errors are
48518 * SyntaxErrors but they can also be out-of-memory errors and
48519 * the like.
48520 */
48521
48522 /* [ ... error ] */
48523
48524 DUK_ASSERT(duk_is_object(thr, -1));
48525
48526 if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
48527 return;
48528 }
48529
48530 DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
48531 (duk_tval *) duk_get_tval(thr, -1)));
48532
48533 if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) {
48534 duk_bool_t at_end;
48535
48536 /* Best guesstimate that error occurred at end of input, token
48537 * truncated by end of input, etc.
48538 */
48539#if 0
48540 at_end = (thr->compile_ctx->curr_token.start_offset + 1 >= thr->compile_ctx->lex.input_length);
48541 at_end = (thr->compile_ctx->lex.window[0].codepoint < 0 || thr->compile_ctx->lex.window[1].codepoint < 0);
48542#endif
48543 at_end = (thr->compile_ctx->lex.window[0].codepoint < 0);
48544
48545 DUK_D(DUK_DPRINT("syntax error, determined at_end=%ld; curr_token.start_offset=%ld, "
48546 "lex.input_length=%ld, window[0].codepoint=%ld, window[1].codepoint=%ld",
48547 (long) at_end,
48548 (long) thr->compile_ctx->curr_token.start_offset,
48549 (long) thr->compile_ctx->lex.input_length,
48550 (long) thr->compile_ctx->lex.window[0].codepoint,
48551 (long) thr->compile_ctx->lex.window[1].codepoint));
48552
48553 duk_push_sprintf(thr, " (line %ld%s)",
48554 (long) thr->compile_ctx->curr_token.start_line,
48555 at_end ? ", end of input" : "");
48556 duk_concat(thr, 2);
48557 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
48558 } else {
48559 duk_pop(thr);
48560 }
48561
48562 DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
48563 (duk_tval *) duk_get_tval(thr, -1)));
48564}
48565#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
48566
48567/*
48568 * Augment an error being created using Duktape specific properties
48569 * like _Tracedata or .fileName/.lineNumber.
48570 */
48571
48572#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
48573DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_hobject *obj, duk_small_uint_t flags) {
48574#if defined(DUK_USE_ASSERTIONS)
48575 duk_int_t entry_top;
48576#endif
48577
48578#if defined(DUK_USE_ASSERTIONS)
48579 entry_top = duk_get_top(thr);
48580#endif
48581 DUK_ASSERT(obj != NULL);
48582
48583 DUK_UNREF(obj); /* unreferenced w/o tracebacks */
48584
48585 duk__add_compiler_error_line(thr);
48586
48587#if defined(DUK_USE_TRACEBACKS)
48588 /* If tracebacks are enabled, the '_Tracedata' property is the only
48589 * thing we need: 'fileName' and 'lineNumber' are virtual properties
48590 * which use '_Tracedata'. (Check _Tracedata only as own property.)
48591 */
48592 if (duk_hobject_find_entry_tval_ptr_stridx(thr->heap, obj, DUK_STRIDX_INT_TRACEDATA) != NULL) {
48593 DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
48594 } else {
48595 duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags);
48596 }
48597#else
48598 /* Without tracebacks the concrete .fileName and .lineNumber need
48599 * to be added directly.
48600 */
48601 duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags);
48602#endif
48603
48604#if defined(DUK_USE_ASSERTIONS)
48605 DUK_ASSERT(duk_get_top(thr) == entry_top);
48606#endif
48607}
48608#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
48609
48610/*
48611 * Augment an error at creation time with _Tracedata/fileName/lineNumber
48612 * and allow a user error handler (if defined) to process/replace the error.
48613 * The error to be augmented is at the stack top.
48614 *
48615 * thr: thread containing the error value
48616 * thr_callstack: thread which should be used for generating callstack etc.
48617 * c_filename: C __FILE__ related to the error
48618 * c_line: C __LINE__ related to the error
48619 * flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE:
48620 * if true, don't fileName/line as error source, otherwise use traceback
48621 * (needed because user code filename/line are reported but internal ones
48622 * are not)
48623 */
48624
48625#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
48626DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) {
48627 duk_hobject *obj;
48628
48629 DUK_ASSERT(thr != NULL);
48630 DUK_ASSERT(thr_callstack != NULL);
48631
48632 /* [ ... error ] */
48633
48634 /*
48635 * Criteria for augmenting:
48636 *
48637 * - augmentation enabled in build (naturally)
48638 * - error value internal prototype chain contains the built-in
48639 * Error prototype object (i.e. 'val instanceof Error')
48640 *
48641 * Additional criteria for built-in augmenting:
48642 *
48643 * - error value is an extensible object
48644 */
48645
48646 obj = duk_get_hobject(thr, -1);
48647 if (!obj) {
48648 DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
48649 return;
48650 }
48651 if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
48652 /* If the value has a prototype loop, it's critical not to
48653 * throw here. Instead, assume the value is not to be
48654 * augmented.
48655 */
48656 DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
48657 return;
48658 }
48659 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
48660 DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
48661 duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags);
48662 } else {
48663 DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
48664 }
48665
48666 /* [ ... error ] */
48667
48668#if defined(DUK_USE_ERRCREATE)
48669 duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
48670#endif
48671}
48672#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
48673
48674/*
48675 * Augment an error at throw time; allow a user error handler (if defined)
48676 * to process/replace the error. The error to be augmented is at the
48677 * stack top.
48678 */
48679
48680#if defined(DUK_USE_AUGMENT_ERROR_THROW)
48681DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
48682#if defined(DUK_USE_ERRTHROW)
48683 duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
48684#endif /* DUK_USE_ERRTHROW */
48685}
48686#endif /* DUK_USE_AUGMENT_ERROR_THROW */
48687#line 1 "duk_error_longjmp.c"
48688/*
48689 * Do a longjmp call, calling the fatal error handler if no
48690 * catchpoint exists.
48691 */
48692
48693/* #include duk_internal.h -> already included */
48694
48695#if defined(DUK_USE_PREFER_SIZE)
48696DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr));
48697DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
48698 (void) duk_fatal(thr, "uncaught error");
48699 DUK_WO_NORETURN(return;);
48700}
48701#endif
48702
48703#if 0
48704DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr));
48705DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
48706 const char *summary;
48707 char buf[DUK_USE_FATAL_MAXLEN];
48708
48709 summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1);
48710 DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
48711 buf[sizeof(buf) - 1] = (char) 0;
48712 (void) duk_fatal(thr, (const char *) buf);
48713 DUK_WO_NORETURN(return;);
48714}
48715#endif
48716
48717#if !defined(DUK_USE_PREFER_SIZE)
48718DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr));
48719DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
48720 const char *summary;
48721 char buf[DUK_USE_FATAL_MAXLEN];
48722
48723 summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1);
48724 DUK_ASSERT(summary != NULL);
48725 DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
48726 buf[sizeof(buf) - 1] = (char) 0;
48727 (void) duk_fatal(thr, (const char *) buf);
48728 DUK_WO_NORETURN(return;);
48729}
48730#endif
48731
48732DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
48733 DUK_ASSERT(thr != NULL);
48734 DUK_ASSERT(thr->heap != NULL);
48735
48736 DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
48737 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
48738 &thr->heap->lj.value1, &thr->heap->lj.value2));
48739
48740 /* Prevent finalizer execution during error handling. All error
48741 * handling sites will process pending finalizers once error handling
48742 * is complete and we're ready for the side effects. Does not prevent
48743 * refzero freeing or mark-and-sweep during error handling.
48744 *
48745 * NOTE: when we come here some calling code may have used DECREF
48746 * NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call.
48747 * We don't want to do it here because it would just check for
48748 * pending finalizers and we prevent that explicitly. Instead,
48749 * the error catcher will run the finalizers once error handling
48750 * is complete.
48751 */
48752
48753 DUK_ASSERT_LJSTATE_SET(thr->heap);
48754
48755 thr->heap->pf_prevent_count++;
48756 DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
48757
48758#if defined(DUK_USE_ASSERTIONS)
48759 /* XXX: set this immediately when longjmp state is set */
48760 DUK_ASSERT(thr->heap->error_not_allowed == 0); /* Detect error within critical section. */
48761 thr->heap->error_not_allowed = 1;
48762#endif
48763
48764 DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count));
48765
48766 /* If we don't have a jmpbuf_ptr, there is little we can do except
48767 * cause a fatal error. The caller's expectation is that we never
48768 * return.
48769 */
48770 if (!thr->heap->lj.jmpbuf_ptr) {
48771 DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
48772 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
48773 &thr->heap->lj.value1, &thr->heap->lj.value2));
48774
48775#if defined(DUK_USE_PREFER_SIZE)
48776 duk__uncaught_minimal(thr);
48777#else
48778 duk__uncaught_error_aware(thr);
48779#endif
48780 DUK_UNREACHABLE();
48781 }
48782
48783#if defined(DUK_USE_CPP_EXCEPTIONS)
48784 throw duk_internal_exception(); /* dummy */
48785#else
48786 DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
48787#endif
48788
48789 DUK_UNREACHABLE();
48790}
48791#line 1 "duk_error_misc.c"
48792/*
48793 * Error helpers
48794 */
48795
48796/* #include duk_internal.h -> already included */
48797
48798/*
48799 * Helper to walk the thread chain and see if there is an active error
48800 * catcher. Protected calls or finally blocks aren't considered catching.
48801 */
48802
48803#if defined(DUK_USE_DEBUGGER_SUPPORT)
48804DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
48805 /* As noted above, a protected API call won't be counted as a
48806 * catcher. This is usually convenient, e.g. in the case of a top-
48807 * level duk_pcall(), but may not always be desirable. Perhaps add
48808 * an argument to treat them as catchers?
48809 */
48810
48811 duk_activation *act;
48812 duk_catcher *cat;
48813
48814 DUK_ASSERT(thr != NULL);
48815
48816 for (; thr != NULL; thr = thr->resumer) {
48817 for (act = thr->callstack_curr; act != NULL; act = act->parent) {
48818 for (cat = act->cat; cat != NULL; cat = cat->parent) {
48819 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
48820 return 1; /* all we need to know */
48821 }
48822 }
48823 }
48824 }
48825 return 0;
48826}
48827#endif /* DUK_USE_DEBUGGER_SUPPORT */
48828
48829/*
48830 * Get prototype object for an integer error code.
48831 */
48832
48833DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
48834 switch (code) {
48835 case DUK_ERR_EVAL_ERROR:
48836 return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
48837 case DUK_ERR_RANGE_ERROR:
48838 return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
48839 case DUK_ERR_REFERENCE_ERROR:
48840 return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
48841 case DUK_ERR_SYNTAX_ERROR:
48842 return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
48843 case DUK_ERR_TYPE_ERROR:
48844 return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
48845 case DUK_ERR_URI_ERROR:
48846 return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
48847 case DUK_ERR_ERROR:
48848 default:
48849 return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
48850 }
48851}
48852
48853/*
48854 * Helper for debugger throw notify and pause-on-uncaught integration.
48855 */
48856
48857#if defined(DUK_USE_DEBUGGER_SUPPORT)
48858DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
48859 duk_bool_t uncaught;
48860 duk_tval *tv_obj;
48861
48862 /* If something is thrown with the debugger attached and nobody will
48863 * catch it, execution is paused before the longjmp, turning over
48864 * control to the debug client. This allows local state to be examined
48865 * before the stack is unwound. Errors are not intercepted when debug
48866 * message loop is active (e.g. for Eval).
48867 */
48868
48869 DUK_ASSERT(thr != NULL);
48870 DUK_ASSERT(thr->heap != NULL);
48871
48872 /* XXX: Allow customizing the pause and notify behavior at runtime
48873 * using debugger runtime flags. For now the behavior is fixed using
48874 * config options.
48875 */
48876
48877 if (!duk_debug_is_attached(thr->heap) ||
48878 thr->heap->dbg_processing ||
48879 thr->heap->lj.type != DUK_LJ_TYPE_THROW ||
48880 thr->heap->creating_error) {
48881 DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error"));
48882 return;
48883 }
48884
48885 /* Don't intercept a DoubleError, we may have caused the initial double
48886 * fault and attempting to intercept it will cause us to be called
48887 * recursively and exhaust the C stack. (This should no longer happen
48888 * for the initial throw because DoubleError path doesn't do a debugger
48889 * integration check, but it might happen for rethrows.)
48890 */
48891 tv_obj = &thr->heap->lj.value1;
48892 if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
48893 DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting"));
48894 return;
48895 }
48896
48897 uncaught = !duk__have_active_catcher(thr);
48898
48899 /* Debugger code expects the value at stack top. This also serves
48900 * as a backup: we need to store/restore the longjmp state because
48901 * when the debugger is paused Eval commands may be executed and
48902 * they can arbitrarily clobber the longjmp state.
48903 */
48904 duk_push_tval(thr, tv_obj);
48905
48906 /* Store and reset longjmp state. */
48907 DUK_ASSERT_LJSTATE_SET(thr->heap);
48908 DUK_TVAL_DECREF_NORZ(thr, tv_obj);
48909 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); /* Always for THROW type. */
48910 DUK_TVAL_SET_UNDEFINED(tv_obj);
48911 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
48912 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
48913
48914#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
48915 /* Report it to the debug client */
48916 DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
48917 duk_debug_send_throw(thr, uncaught);
48918#endif
48919
48920 if (uncaught) {
48921 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) {
48922 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error"));
48923 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
48924 }
48925 } else {
48926 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) {
48927 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error"));
48928 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
48929 }
48930 }
48931
48932 /* Restore longjmp state. */
48933 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
48934 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
48935 tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1);
48936 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
48937 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
48938 DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj);
48939 DUK_TVAL_INCREF(thr, tv_obj);
48940 DUK_ASSERT_LJSTATE_SET(thr->heap);
48941
48942 duk_pop(thr);
48943}
48944#endif /* DUK_USE_DEBUGGER_SUPPORT */
48945
48946/*
48947 * Helpers for setting up heap longjmp state.
48948 */
48949
48950DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) {
48951 duk_heap *heap;
48952
48953 DUK_ASSERT(thr != NULL);
48954 heap = thr->heap;
48955 DUK_ASSERT(heap != NULL);
48956 DUK_ASSERT(tv_val != NULL);
48957
48958 DUK_ASSERT_LJSTATE_UNSET(heap);
48959
48960 heap->lj.type = lj_type;
48961 DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val);
48962 DUK_TVAL_INCREF(thr, tv_val);
48963
48964 DUK_ASSERT_LJSTATE_SET(heap);
48965}
48966#line 1 "duk_error_throw.c"
48967/*
48968 * Create and throw an ECMAScript error object based on a code and a message.
48969 *
48970 * Used when we throw errors internally. ECMAScript generated error objects
48971 * are created by ECMAScript code, and the throwing is handled by the bytecode
48972 * executor.
48973 */
48974
48975/* #include duk_internal.h -> already included */
48976
48977/*
48978 * Create and throw an error (originating from Duktape internally)
48979 *
48980 * Push an error object on top of the stack, possibly throw augmenting
48981 * the error, and finally longjmp.
48982 *
48983 * If an error occurs while we're dealing with the current error, we might
48984 * enter an infinite recursion loop. This is prevented by detecting a
48985 * "double fault" through the heap->creating_error flag; the recursion
48986 * then stops at the second level.
48987 */
48988
48989#if defined(DUK_USE_VERBOSE_ERRORS)
48990DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
48991#else
48992DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
48993#endif
48994#if defined(DUK_USE_VERBOSE_ERRORS)
48995 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
48996 (long) code, (const char *) msg,
48997 (const char *) filename, (long) line));
48998#else
48999 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
49000#endif
49001
49002 DUK_ASSERT(thr != NULL);
49003
49004 /* Even though nested call is possible because we throw an error when
49005 * trying to create an error, the potential errors must happen before
49006 * the longjmp state is configured.
49007 */
49008 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
49009
49010 /* Sync so that augmentation sees up-to-date activations, NULL
49011 * thr->ptr_curr_pc so that it's not used if side effects occur
49012 * in augmentation or longjmp handling.
49013 */
49014 duk_hthread_sync_and_null_currpc(thr);
49015
49016 /*
49017 * Create and push an error object onto the top of stack.
49018 * The error is potentially augmented before throwing.
49019 *
49020 * If a "double error" occurs, use a fixed error instance
49021 * to avoid further trouble.
49022 */
49023
49024 if (thr->heap->creating_error) {
49025 duk_tval tv_val;
49026 duk_hobject *h_err;
49027
49028 thr->heap->creating_error = 0;
49029
49030 h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR];
49031 if (h_err != NULL) {
49032 DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance"));
49033 DUK_TVAL_SET_OBJECT(&tv_val, h_err);
49034 } else {
49035 DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
49036 "-> use the error code as a number"));
49037 DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code);
49038 }
49039
49040 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val);
49041
49042 /* No augmentation to avoid any allocations or side effects. */
49043 } else {
49044 /* Prevent infinite recursion. Extra call stack and C
49045 * recursion headroom (see GH-191) is added for augmentation.
49046 * That is now signalled by heap->augmenting error and taken
49047 * into account in call handling without an explicit limit bump.
49048 */
49049 thr->heap->creating_error = 1;
49050
49051 duk_require_stack(thr, 1);
49052
49053 /* XXX: usually unnecessary '%s' formatting here, but cannot
49054 * use 'msg' as a format string directly.
49055 */
49056#if defined(DUK_USE_VERBOSE_ERRORS)
49057 duk_push_error_object_raw(thr,
49058 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
49059 filename,
49060 line,
49061 "%s",
49062 (const char *) msg);
49063#else
49064 duk_push_error_object_raw(thr,
49065 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
49066 NULL,
49067 0,
49068 NULL);
49069#endif
49070
49071 /* Note that an alloc error may happen during error augmentation.
49072 * This may happen both when the original error is an alloc error
49073 * and when it's something else. Because any error in augmentation
49074 * must be handled correctly anyway, there's no special check for
49075 * avoiding it for alloc errors (this differs from Duktape 1.x).
49076 */
49077#if defined(DUK_USE_AUGMENT_ERROR_THROW)
49078 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
49079 (duk_tval *) duk_get_tval(thr, -1)));
49080 duk_err_augment_error_throw(thr);
49081#endif
49082
49083 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
49084 thr->heap->creating_error = 0;
49085
49086 /* Error is now created and we assume no errors can occur any
49087 * more. Check for debugger Throw integration only when the
49088 * error is complete. If we enter debugger message loop,
49089 * creating_error must be 0 so that errors can be thrown in
49090 * the paused state, e.g. in Eval commands.
49091 */
49092#if defined(DUK_USE_DEBUGGER_SUPPORT)
49093 duk_err_check_debugger_integration(thr);
49094#endif
49095 }
49096
49097 /*
49098 * Finally, longjmp
49099 */
49100
49101 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
49102 (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
49103
49104 duk_err_longjmp(thr);
49105 DUK_UNREACHABLE();
49106}
49107
49108/*
49109 * Helper for C function call negative return values.
49110 */
49111
49112DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
49113 DUK_ASSERT(thr != NULL);
49114 DUK_ASSERT(rc < 0);
49115
49116 /*
49117 * The __FILE__ and __LINE__ information is intentionally not used in the
49118 * creation of the error object, as it isn't useful in the tracedata. The
49119 * tracedata still contains the function which returned the negative return
49120 * code, and having the file/line of this function isn't very useful.
49121 *
49122 * The error messages for DUK_RET_xxx shorthand are intentionally very
49123 * minimal: they're only really useful for low memory targets.
49124 */
49125
49126 duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
49127 DUK_WO_NORETURN(return;);
49128}
49129#line 1 "duk_hbuffer_alloc.c"
49130/*
49131 * duk_hbuffer allocation and freeing.
49132 */
49133
49134/* #include duk_internal.h -> already included */
49135
49136/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
49137 * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
49138 * allocation successful).
49139 */
49140DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
49141 duk_hbuffer *res = NULL;
49142 duk_size_t header_size;
49143 duk_size_t alloc_size;
49144
49145 DUK_ASSERT(heap != NULL);
49146 DUK_ASSERT(out_bufdata != NULL);
49147
49148 DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
49149
49150 /* Size sanity check. Should not be necessary because caller is
49151 * required to check this, but we don't want to cause a segfault
49152 * if the size wraps either in duk_size_t computation or when
49153 * storing the size in a 16-bit field.
49154 */
49155 if (size > DUK_HBUFFER_MAX_BYTELEN) {
49156 DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
49157 return NULL; /* no need to write 'out_bufdata' */
49158 }
49159
49160 if (flags & DUK_BUF_FLAG_EXTERNAL) {
49161 header_size = sizeof(duk_hbuffer_external);
49162 alloc_size = sizeof(duk_hbuffer_external);
49163 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
49164 header_size = sizeof(duk_hbuffer_dynamic);
49165 alloc_size = sizeof(duk_hbuffer_dynamic);
49166 } else {
49167 header_size = sizeof(duk_hbuffer_fixed);
49168 alloc_size = sizeof(duk_hbuffer_fixed) + size;
49169 DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
49170 }
49171
49172 res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
49173 if (DUK_UNLIKELY(res == NULL)) {
49174 goto alloc_error;
49175 }
49176
49177 /* zero everything unless requested not to do so */
49178#if defined(DUK_USE_ZERO_BUFFER_DATA)
49179 duk_memzero((void *) res,
49180 (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
49181#else
49182 duk_memzero((void *) res, header_size);
49183#endif
49184
49185 if (flags & DUK_BUF_FLAG_EXTERNAL) {
49186 duk_hbuffer_external *h;
49187 h = (duk_hbuffer_external *) res;
49188 DUK_UNREF(h);
49189 *out_bufdata = NULL;
49190#if defined(DUK_USE_EXPLICIT_NULL_INIT)
49191#if defined(DUK_USE_HEAPPTR16)
49192/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
49193#else
49194 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
49195#endif
49196#endif
49197 DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
49198 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
49199 duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
49200 void *ptr;
49201
49202 if (size > 0) {
49203 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
49204 DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
49205#if defined(DUK_USE_ZERO_BUFFER_DATA)
49206 ptr = DUK_ALLOC_ZEROED(heap, size);
49207#else
49208 ptr = DUK_ALLOC(heap, size);
49209#endif
49210 if (DUK_UNLIKELY(ptr == NULL)) {
49211 /* Because size > 0, NULL check is correct */
49212 goto alloc_error;
49213 }
49214 *out_bufdata = ptr;
49215
49216 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
49217 } else {
49218 *out_bufdata = NULL;
49219#if defined(DUK_USE_EXPLICIT_NULL_INIT)
49220#if defined(DUK_USE_HEAPPTR16)
49221/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
49222#else
49223 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
49224#endif
49225#endif
49226 DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
49227 }
49228 } else {
49229 *out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1);
49230 }
49231
49232 DUK_HBUFFER_SET_SIZE(res, size);
49233
49234 DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
49235 if (flags & DUK_BUF_FLAG_DYNAMIC) {
49236 DUK_HBUFFER_SET_DYNAMIC(res);
49237 if (flags & DUK_BUF_FLAG_EXTERNAL) {
49238 DUK_HBUFFER_SET_EXTERNAL(res);
49239 }
49240 } else {
49241 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
49242 }
49243 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
49244
49245 DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
49246 return res;
49247
49248 alloc_error:
49249 DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
49250
49251 DUK_FREE(heap, res);
49252 return NULL; /* no need to write 'out_bufdata' */
49253}
49254
49255/* For indirect allocs. */
49256
49257DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
49258 duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
49259 DUK_UNREF(heap);
49260 return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
49261}
49262#line 1 "duk_hbuffer_assert.c"
49263/*
49264 * duk_hbuffer assertion helpers
49265 */
49266
49267/* #include duk_internal.h -> already included */
49268
49269#if defined(DUK_USE_ASSERTIONS)
49270
49271DUK_INTERNAL void duk_hbuffer_assert_valid(duk_hbuffer *h) {
49272 DUK_ASSERT(h != NULL);
49273}
49274
49275#endif /* DUK_USE_ASSERTIONS */
49276#line 1 "duk_hbuffer_ops.c"
49277/*
49278 * duk_hbuffer operations such as resizing and inserting/appending data to
49279 * a dynamic buffer.
49280 */
49281
49282/* #include duk_internal.h -> already included */
49283
49284/*
49285 * Resizing
49286 */
49287
49288DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
49289 void *res;
49290 duk_size_t prev_size;
49291
49292 DUK_ASSERT(thr != NULL);
49293 DUK_ASSERT(buf != NULL);
49294 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
49295 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
49296
49297 /*
49298 * Maximum size check
49299 */
49300
49301 if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
49302 DUK_ERROR_RANGE(thr, "buffer too long");
49303 DUK_WO_NORETURN(return;);
49304 }
49305
49306 /*
49307 * Note: use indirect realloc variant just in case mark-and-sweep
49308 * (finalizers) might resize this same buffer during garbage
49309 * collection.
49310 */
49311
49312 res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
49313 if (DUK_LIKELY(res != NULL || new_size == 0)) {
49314 /* 'res' may be NULL if new allocation size is 0. */
49315
49316 DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
49317 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
49318 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
49319 (void *) res,
49320 (long) new_size));
49321
49322 /*
49323 * The entire allocated buffer area, regardless of actual used
49324 * size, is kept zeroed in resizes for simplicity. If the buffer
49325 * is grown, zero the new part.
49326 */
49327
49328 prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
49329 if (new_size > prev_size) {
49330 DUK_ASSERT(new_size - prev_size > 0);
49331#if defined(DUK_USE_ZERO_BUFFER_DATA)
49332 duk_memzero((void *) ((char *) res + prev_size),
49333 (duk_size_t) (new_size - prev_size));
49334#endif
49335 }
49336
49337 DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
49338 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
49339 } else {
49340 DUK_ERROR_ALLOC_FAILED(thr);
49341 DUK_WO_NORETURN(return;);
49342 }
49343
49344 DUK_ASSERT(res != NULL || new_size == 0);
49345}
49346
49347DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
49348 DUK_ASSERT(thr != NULL);
49349 DUK_ASSERT(buf != NULL);
49350 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
49351 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
49352
49353 duk_hbuffer_resize(thr, buf, 0);
49354}
49355/* #include duk_internal.h -> already included */
49356#line 2 "duk_hbufobj_misc.c"
49357
49358#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
49359DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) {
49360 duk_uint_t buf_size;
49361 duk_uint_t buf_avail;
49362
49363 DUK_ASSERT(h_bufobj != NULL);
49364 DUK_ASSERT(h_bufobj->buf != NULL);
49365
49366 buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
49367 if (h_bufobj->offset > buf_size) {
49368 /* Slice starting point is beyond current length. */
49369 return 0;
49370 }
49371 buf_avail = buf_size - h_bufobj->offset;
49372
49373 return buf_avail >= len ? len : buf_avail;
49374}
49375#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
49376#line 1 "duk_heap_alloc.c"
49377/*
49378 * duk_heap allocation and freeing.
49379 */
49380
49381/* #include duk_internal.h -> already included */
49382
49383#if defined(DUK_USE_ROM_STRINGS)
49384/* Fixed seed value used with ROM strings. */
49385#define DUK__FIXED_HASH_SEED 0xabcd1234
49386#endif
49387
49388/*
49389 * Free a heap object.
49390 *
49391 * Free heap object and its internal (non-heap) pointers. Assumes that
49392 * caller has removed the object from heap allocated list or the string
49393 * intern table, and any weak references (which strings may have) have
49394 * been already dealt with.
49395 */
49396
49397DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
49398 DUK_ASSERT(heap != NULL);
49399 DUK_ASSERT(h != NULL);
49400
49401 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
49402
49403 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
49404 duk_hcompfunc *f = (duk_hcompfunc *) h;
49405 DUK_UNREF(f);
49406 /* Currently nothing to free; 'data' is a heap object */
49407 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
49408 duk_hnatfunc *f = (duk_hnatfunc *) h;
49409 DUK_UNREF(f);
49410 /* Currently nothing to free */
49411 } else if (DUK_HOBJECT_IS_THREAD(h)) {
49412 duk_hthread *t = (duk_hthread *) h;
49413 duk_activation *act;
49414
49415 DUK_FREE(heap, t->valstack);
49416
49417 /* Don't free h->resumer because it exists in the heap.
49418 * Callstack entries also contain function pointers which
49419 * are not freed for the same reason. They are decref
49420 * finalized and the targets are freed if necessary based
49421 * on their refcount (or reachability).
49422 */
49423 for (act = t->callstack_curr; act != NULL;) {
49424 duk_activation *act_next;
49425 duk_catcher *cat;
49426
49427 for (cat = act->cat; cat != NULL;) {
49428 duk_catcher *cat_next;
49429
49430 cat_next = cat->parent;
49431 DUK_FREE(heap, (void *) cat);
49432 cat = cat_next;
49433 }
49434
49435 act_next = act->parent;
49436 DUK_FREE(heap, (void *) act);
49437 act = act_next;
49438 }
49439
49440 /* XXX: with 'caller' property the callstack would need
49441 * to be unwound to update the 'caller' properties of
49442 * functions in the callstack.
49443 */
49444 } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
49445 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
49446
49447 DUK_FREE(heap, f->args);
49448 }
49449
49450 DUK_FREE(heap, (void *) h);
49451}
49452
49453DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) {
49454 DUK_ASSERT(heap != NULL);
49455 DUK_ASSERT(h != NULL);
49456
49457 if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
49458 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
49459 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
49460 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
49461 }
49462 DUK_FREE(heap, (void *) h);
49463}
49464
49465DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) {
49466 DUK_ASSERT(heap != NULL);
49467 DUK_ASSERT(h != NULL);
49468
49469 DUK_UNREF(heap);
49470 DUK_UNREF(h);
49471
49472#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
49473 if (DUK_HSTRING_HAS_EXTDATA(h)) {
49474 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
49475 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
49476 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
49477 }
49478#endif
49479 DUK_FREE(heap, (void *) h);
49480}
49481
49482DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
49483 DUK_ASSERT(heap);
49484 DUK_ASSERT(hdr);
49485
49486 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
49487
49488 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
49489 case DUK_HTYPE_STRING:
49490 duk_free_hstring(heap, (duk_hstring *) hdr);
49491 break;
49492 case DUK_HTYPE_OBJECT:
49493 duk_free_hobject(heap, (duk_hobject *) hdr);
49494 break;
49495 default:
49496 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER);
49497 duk_free_hbuffer(heap, (duk_hbuffer *) hdr);
49498 }
49499
49500}
49501
49502/*
49503 * Free the heap.
49504 *
49505 * Frees heap-related non-heap-tracked allocations such as the
49506 * string intern table; then frees the heap allocated objects;
49507 * and finally frees the heap structure itself. Reference counts
49508 * and GC markers are ignored (and not updated) in this process,
49509 * and finalizers won't be called.
49510 *
49511 * The heap pointer and heap object pointers must not be used
49512 * after this call.
49513 */
49514
49515#if defined(DUK_USE_CACHE_ACTIVATION)
49516DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) {
49517 duk_activation *act;
49518 duk_activation *act_next;
49519 duk_size_t count_act = 0;
49520
49521 for (act = heap->activation_free; act != NULL;) {
49522 act_next = act->parent;
49523 DUK_FREE(heap, (void *) act);
49524 act = act_next;
49525#if defined(DUK_USE_DEBUG)
49526 count_act++;
49527#endif
49528 }
49529 heap->activation_free = NULL; /* needed when called from mark-and-sweep */
49530 return count_act;
49531}
49532#endif /* DUK_USE_CACHE_ACTIVATION */
49533
49534#if defined(DUK_USE_CACHE_CATCHER)
49535DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) {
49536 duk_catcher *cat;
49537 duk_catcher *cat_next;
49538 duk_size_t count_cat = 0;
49539
49540 for (cat = heap->catcher_free; cat != NULL;) {
49541 cat_next = cat->parent;
49542 DUK_FREE(heap, (void *) cat);
49543 cat = cat_next;
49544#if defined(DUK_USE_DEBUG)
49545 count_cat++;
49546#endif
49547 }
49548 heap->catcher_free = NULL; /* needed when called from mark-and-sweep */
49549
49550 return count_cat;
49551}
49552#endif /* DUK_USE_CACHE_CATCHER */
49553
49554DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) {
49555 duk_size_t count_act = 0;
49556 duk_size_t count_cat = 0;
49557
49558#if defined(DUK_USE_CACHE_ACTIVATION)
49559 count_act = duk__heap_free_activation_freelist(heap);
49560#endif
49561#if defined(DUK_USE_CACHE_CATCHER)
49562 count_cat = duk__heap_free_catcher_freelist(heap);
49563#endif
49564 DUK_UNREF(heap);
49565 DUK_UNREF(count_act);
49566 DUK_UNREF(count_cat);
49567
49568 DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries",
49569 (long) count_act, (long) count_cat));
49570}
49571
49572DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
49573 duk_heaphdr *curr;
49574 duk_heaphdr *next;
49575
49576 curr = heap->heap_allocated;
49577 while (curr) {
49578 /* We don't log or warn about freeing zero refcount objects
49579 * because they may happen with finalizer processing.
49580 */
49581
49582 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
49583 (duk_heaphdr *) curr));
49584 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
49585 duk_heap_free_heaphdr_raw(heap, curr);
49586 curr = next;
49587 }
49588}
49589
49590#if defined(DUK_USE_FINALIZER_SUPPORT)
49591DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) {
49592 duk_heaphdr *curr;
49593 duk_heaphdr *next;
49594
49595 curr = heap->finalize_list;
49596 while (curr) {
49597 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
49598 (duk_heaphdr *) curr));
49599 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
49600 duk_heap_free_heaphdr_raw(heap, curr);
49601 curr = next;
49602 }
49603}
49604#endif /* DUK_USE_FINALIZER_SUPPORT */
49605
49606DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
49607 /* strings are only tracked by stringtable */
49608 duk_heap_strtable_free(heap);
49609}
49610
49611#if defined(DUK_USE_FINALIZER_SUPPORT)
49612DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
49613 duk_heaphdr *curr;
49614 duk_uint_t round_no;
49615 duk_size_t count_all;
49616 duk_size_t count_finalized;
49617 duk_size_t curr_limit;
49618
49619 DUK_ASSERT(heap != NULL);
49620
49621#if defined(DUK_USE_REFERENCE_COUNTING)
49622 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
49623#endif
49624 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */
49625
49626 if (heap->heap_thread == NULL) {
49627 /* May happen when heap allocation fails right off. There
49628 * cannot be any finalizable objects in this case.
49629 */
49630 DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects"));
49631 return;
49632 }
49633
49634 /* Prevent finalize_list processing and mark-and-sweep entirely.
49635 * Setting ms_running != 0 also prevents refzero handling from moving
49636 * objects away from the heap_allocated list. The flag name is a bit
49637 * misleading here.
49638 *
49639 * Use a distinct value for ms_running here (== 2) so that assertions
49640 * can detect this situation separate from the normal runtime
49641 * mark-and-sweep case. This allows better assertions (GH-2030).
49642 */
49643 DUK_ASSERT(heap->pf_prevent_count == 0);
49644 DUK_ASSERT(heap->ms_running == 0);
49645 DUK_ASSERT(heap->ms_prevent_count == 0);
49646 heap->pf_prevent_count = 1;
49647 heap->ms_running = 2; /* Use distinguishable value. */
49648 heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */
49649
49650 curr_limit = 0; /* suppress warning, not used */
49651 for (round_no = 0; ; round_no++) {
49652 curr = heap->heap_allocated;
49653 count_all = 0;
49654 count_finalized = 0;
49655 while (curr) {
49656 count_all++;
49657 if (DUK_HEAPHDR_IS_OBJECT(curr)) {
49658 /* Only objects in heap_allocated may have finalizers. Check that
49659 * the object itself has a _Finalizer property (own or inherited)
49660 * so that we don't execute finalizers for e.g. Proxy objects.
49661 */
49662 DUK_ASSERT(curr != NULL);
49663
49664 if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) {
49665 if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
49666 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
49667 duk_heap_run_finalizer(heap, (duk_hobject *) curr);
49668 count_finalized++;
49669 }
49670 }
49671 }
49672 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
49673 }
49674
49675 /* Each round of finalizer execution may spawn new finalizable objects
49676 * which is normal behavior for some applications. Allow multiple
49677 * rounds of finalization, but use a shrinking limit based on the
49678 * first round to detect the case where a runaway finalizer creates
49679 * an unbounded amount of new finalizable objects. Finalizer rescue
49680 * is not supported: the semantics are unclear because most of the
49681 * objects being finalized here are already reachable. The finalizer
49682 * is given a boolean to indicate that rescue is not possible.
49683 *
49684 * See discussion in: https://github.com/svaarala/duktape/pull/473
49685 */
49686
49687 if (round_no == 0) {
49688 /* Cannot wrap: each object is at least 8 bytes so count is
49689 * at most 1/8 of that.
49690 */
49691 curr_limit = count_all * 2;
49692 } else {
49693 curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
49694 }
49695 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
49696 (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
49697
49698 if (count_finalized == 0) {
49699 DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
49700 break;
49701 }
49702 if (count_finalized >= curr_limit) {
49703 DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
49704 break;
49705 }
49706 }
49707
49708 DUK_ASSERT(heap->ms_running == 2);
49709 DUK_ASSERT(heap->pf_prevent_count == 1);
49710 heap->ms_running = 0;
49711 heap->pf_prevent_count = 0;
49712}
49713#endif /* DUK_USE_FINALIZER_SUPPORT */
49714
49715DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
49716 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
49717
49718#if defined(DUK_USE_DEBUG)
49719 duk_heap_strtable_dump(heap);
49720#endif
49721
49722#if defined(DUK_USE_DEBUGGER_SUPPORT)
49723 /* Detach a debugger if attached (can be called multiple times)
49724 * safely.
49725 */
49726 /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
49727 * the detached callback may immediately reattach.
49728 */
49729 duk_debug_do_detach(heap);
49730#endif
49731
49732 /* Execute finalizers before freeing the heap, even for reachable
49733 * objects. This gives finalizers the chance to free any native
49734 * resources like file handles, allocations made outside Duktape,
49735 * etc. This is quite tricky to get right, so that all finalizer
49736 * guarantees are honored.
49737 *
49738 * Run mark-and-sweep a few times just in case (unreachable object
49739 * finalizers run already here). The last round must rescue objects
49740 * from the previous round without running any more finalizers. This
49741 * ensures rescued objects get their FINALIZED flag cleared so that
49742 * their finalizer is called once more in forced finalization to
49743 * satisfy finalizer guarantees. However, we don't want to run any
49744 * more finalizers because that'd required one more loop, and so on.
49745 *
49746 * XXX: this perhaps requires an execution time limit.
49747 */
49748 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
49749 DUK_ASSERT(heap->pf_skip_finalizers == 0);
49750 DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
49751 duk_heap_mark_and_sweep(heap, 0);
49752 DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
49753 duk_heap_mark_and_sweep(heap, 0);
49754 DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
49755 heap->pf_skip_finalizers = 1;
49756 duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */
49757
49758 /* There are never objects in refzero_list at this point, or at any
49759 * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1
49760 * refzero_list processing is side effect free, so it is always
49761 * processed to completion by a DECREF initially triggering a zero
49762 * refcount.
49763 */
49764#if defined(DUK_USE_REFERENCE_COUNTING)
49765 DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */
49766#endif
49767#if defined(DUK_USE_FINALIZER_SUPPORT)
49768 DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */
49769#endif
49770
49771#if defined(DUK_USE_FINALIZER_SUPPORT)
49772 DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects"));
49773 DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */
49774 duk__free_run_finalizers(heap);
49775#endif /* DUK_USE_FINALIZER_SUPPORT */
49776
49777 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
49778 * are on the heap allocated list.
49779 */
49780
49781 DUK_D(DUK_DPRINT("freeing temporary freelists"));
49782 duk_heap_free_freelists(heap);
49783
49784 DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap));
49785 duk__free_allocated(heap);
49786
49787#if defined(DUK_USE_REFERENCE_COUNTING)
49788 DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */
49789#endif
49790
49791#if defined(DUK_USE_FINALIZER_SUPPORT)
49792 DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap));
49793 duk__free_finalize_list(heap);
49794#endif
49795
49796 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
49797 duk__free_stringtable(heap);
49798
49799 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
49800 heap->free_func(heap->heap_udata, heap);
49801}
49802
49803/*
49804 * Allocate a heap.
49805 *
49806 * String table is initialized with built-in strings from genbuiltins.py,
49807 * either by dynamically creating the strings or by referring to ROM strings.
49808 */
49809
49810#if defined(DUK_USE_ROM_STRINGS)
49811DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
49812#if defined(DUK_USE_ASSERTIONS)
49813 duk_small_uint_t i;
49814#endif
49815
49816 DUK_UNREF(heap);
49817
49818 /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
49819 * so nothing to initialize for strs[].
49820 */
49821
49822#if defined(DUK_USE_ASSERTIONS)
49823 for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) {
49824 const duk_hstring *h;
49825 duk_uint32_t hash;
49826
49827 h = duk_rom_strings_lookup[i];
49828 while (h != NULL) {
49829 hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
49830 DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx",
49831 (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
49832 DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
49833
49834 h = (const duk_hstring *) h->hdr.h_next;
49835 }
49836 }
49837#endif
49838 return 1;
49839}
49840#else /* DUK_USE_ROM_STRINGS */
49841
49842DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
49843 duk_bitdecoder_ctx bd_ctx;
49844 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
49845 duk_small_uint_t i;
49846
49847 duk_memzero(&bd_ctx, sizeof(bd_ctx));
49848 bd->data = (const duk_uint8_t *) duk_strings_data;
49849 bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
49850
49851 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
49852 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
49853 duk_small_uint_t len;
49854 duk_hstring *h;
49855
49856 len = duk_bd_decode_bitpacked_string(bd, tmp);
49857
49858 /* No need to length check string: it will never exceed even
49859 * the 16-bit length maximum.
49860 */
49861 DUK_ASSERT(len <= 0xffffUL);
49862 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
49863 h = duk_heap_strtable_intern(heap, tmp, len);
49864 if (!h) {
49865 goto failed;
49866 }
49867 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
49868
49869 /* Special flags checks. Since these strings are always
49870 * reachable and a string cannot appear twice in the string
49871 * table, there's no need to check/set these flags elsewhere.
49872 * The 'internal' flag is set by string intern code.
49873 */
49874 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
49875 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
49876 }
49877 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
49878 DUK_HSTRING_SET_RESERVED_WORD(h);
49879 if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
49880 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
49881 }
49882 }
49883
49884 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
49885
49886 /* XXX: The incref macro takes a thread pointer but doesn't
49887 * use it right now.
49888 */
49889 DUK_HSTRING_INCREF(_never_referenced_, h);
49890
49891#if defined(DUK_USE_HEAPPTR16)
49892 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
49893#else
49894 heap->strs[i] = h;
49895#endif
49896 }
49897
49898 return 1;
49899
49900 failed:
49901 return 0;
49902}
49903#endif /* DUK_USE_ROM_STRINGS */
49904
49905DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
49906 duk_hthread *thr;
49907
49908 DUK_D(DUK_DPRINT("heap init: alloc heap thread"));
49909 thr = duk_hthread_alloc_unchecked(heap,
49910 DUK_HOBJECT_FLAG_EXTENSIBLE |
49911 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
49912 if (thr == NULL) {
49913 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
49914 return 0;
49915 }
49916 thr->state = DUK_HTHREAD_STATE_INACTIVE;
49917#if defined(DUK_USE_ROM_STRINGS)
49918 /* No strs[] pointer. */
49919#else /* DUK_USE_ROM_STRINGS */
49920#if defined(DUK_USE_HEAPPTR16)
49921 thr->strs16 = heap->strs16;
49922#else
49923 thr->strs = heap->strs;
49924#endif
49925#endif /* DUK_USE_ROM_STRINGS */
49926
49927 heap->heap_thread = thr;
49928 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
49929
49930 /* 'thr' is now reachable */
49931
49932 DUK_D(DUK_DPRINT("heap init: init heap thread stacks"));
49933 if (!duk_hthread_init_stacks(heap, thr)) {
49934 return 0;
49935 }
49936
49937 /* XXX: this may now fail, and is not handled correctly */
49938 duk_hthread_create_builtin_objects(thr);
49939
49940 /* default prototype */
49941 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
49942
49943 return 1;
49944}
49945
49946#if defined(DUK_USE_DEBUG)
49947#define DUK__DUMPSZ(t) do { \
49948 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
49949 } while (0)
49950
49951/* These is not 100% because format would need to be non-portable "long long".
49952 * Also print out as doubles to catch cases where the "long" type is not wide
49953 * enough; the limits will then not be printed accurately but the magnitude
49954 * will be correct.
49955 */
49956#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
49957 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
49958 (long) (a), (long) (b), \
49959 (double) (a), (double) (b))); \
49960 } while (0)
49961#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
49962 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
49963 (unsigned long) (a), (unsigned long) (b), \
49964 (double) (a), (double) (b))); \
49965 } while (0)
49966#define DUK__DUMPLM_SIGNED(t) do { \
49967 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
49968 } while (0)
49969#define DUK__DUMPLM_UNSIGNED(t) do { \
49970 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
49971 } while (0)
49972
49973DUK_LOCAL void duk__dump_type_sizes(void) {
49974 DUK_D(DUK_DPRINT("sizeof()"));
49975
49976 /* basic platform types */
49977 DUK__DUMPSZ(char);
49978 DUK__DUMPSZ(short);
49979 DUK__DUMPSZ(int);
49980 DUK__DUMPSZ(long);
49981 DUK__DUMPSZ(double);
49982 DUK__DUMPSZ(void *);
49983 DUK__DUMPSZ(size_t);
49984
49985 /* basic types from duk_features.h */
49986 DUK__DUMPSZ(duk_uint8_t);
49987 DUK__DUMPSZ(duk_int8_t);
49988 DUK__DUMPSZ(duk_uint16_t);
49989 DUK__DUMPSZ(duk_int16_t);
49990 DUK__DUMPSZ(duk_uint32_t);
49991 DUK__DUMPSZ(duk_int32_t);
49992 DUK__DUMPSZ(duk_uint64_t);
49993 DUK__DUMPSZ(duk_int64_t);
49994 DUK__DUMPSZ(duk_uint_least8_t);
49995 DUK__DUMPSZ(duk_int_least8_t);
49996 DUK__DUMPSZ(duk_uint_least16_t);
49997 DUK__DUMPSZ(duk_int_least16_t);
49998 DUK__DUMPSZ(duk_uint_least32_t);
49999 DUK__DUMPSZ(duk_int_least32_t);
50000#if defined(DUK_USE_64BIT_OPS)
50001 DUK__DUMPSZ(duk_uint_least64_t);
50002 DUK__DUMPSZ(duk_int_least64_t);
50003#endif
50004 DUK__DUMPSZ(duk_uint_fast8_t);
50005 DUK__DUMPSZ(duk_int_fast8_t);
50006 DUK__DUMPSZ(duk_uint_fast16_t);
50007 DUK__DUMPSZ(duk_int_fast16_t);
50008 DUK__DUMPSZ(duk_uint_fast32_t);
50009 DUK__DUMPSZ(duk_int_fast32_t);
50010#if defined(DUK_USE_64BIT_OPS)
50011 DUK__DUMPSZ(duk_uint_fast64_t);
50012 DUK__DUMPSZ(duk_int_fast64_t);
50013#endif
50014 DUK__DUMPSZ(duk_uintptr_t);
50015 DUK__DUMPSZ(duk_intptr_t);
50016 DUK__DUMPSZ(duk_uintmax_t);
50017 DUK__DUMPSZ(duk_intmax_t);
50018 DUK__DUMPSZ(duk_double_t);
50019
50020 /* important chosen base types */
50021 DUK__DUMPSZ(duk_int_t);
50022 DUK__DUMPSZ(duk_uint_t);
50023 DUK__DUMPSZ(duk_int_fast_t);
50024 DUK__DUMPSZ(duk_uint_fast_t);
50025 DUK__DUMPSZ(duk_small_int_t);
50026 DUK__DUMPSZ(duk_small_uint_t);
50027 DUK__DUMPSZ(duk_small_int_fast_t);
50028 DUK__DUMPSZ(duk_small_uint_fast_t);
50029
50030 /* some derived types */
50031 DUK__DUMPSZ(duk_codepoint_t);
50032 DUK__DUMPSZ(duk_ucodepoint_t);
50033 DUK__DUMPSZ(duk_idx_t);
50034 DUK__DUMPSZ(duk_errcode_t);
50035 DUK__DUMPSZ(duk_uarridx_t);
50036
50037 /* tval */
50038 DUK__DUMPSZ(duk_double_union);
50039 DUK__DUMPSZ(duk_tval);
50040
50041 /* structs from duk_forwdecl.h */
50042 DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
50043 DUK__DUMPSZ(duk_heaphdr);
50044 DUK__DUMPSZ(duk_heaphdr_string);
50045 DUK__DUMPSZ(duk_hstring);
50046 DUK__DUMPSZ(duk_hstring_external);
50047 DUK__DUMPSZ(duk_hobject);
50048 DUK__DUMPSZ(duk_harray);
50049 DUK__DUMPSZ(duk_hcompfunc);
50050 DUK__DUMPSZ(duk_hnatfunc);
50051 DUK__DUMPSZ(duk_hdecenv);
50052 DUK__DUMPSZ(duk_hobjenv);
50053 DUK__DUMPSZ(duk_hthread);
50054#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
50055 DUK__DUMPSZ(duk_hbufobj);
50056#endif
50057 DUK__DUMPSZ(duk_hproxy);
50058 DUK__DUMPSZ(duk_hbuffer);
50059 DUK__DUMPSZ(duk_hbuffer_fixed);
50060 DUK__DUMPSZ(duk_hbuffer_dynamic);
50061 DUK__DUMPSZ(duk_hbuffer_external);
50062 DUK__DUMPSZ(duk_propaccessor);
50063 DUK__DUMPSZ(duk_propvalue);
50064 DUK__DUMPSZ(duk_propdesc);
50065 DUK__DUMPSZ(duk_heap);
50066 DUK__DUMPSZ(duk_activation);
50067 DUK__DUMPSZ(duk_catcher);
50068 DUK__DUMPSZ(duk_strcache_entry);
50069 DUK__DUMPSZ(duk_litcache_entry);
50070 DUK__DUMPSZ(duk_ljstate);
50071 DUK__DUMPSZ(duk_fixedbuffer);
50072 DUK__DUMPSZ(duk_bitdecoder_ctx);
50073 DUK__DUMPSZ(duk_bitencoder_ctx);
50074 DUK__DUMPSZ(duk_token);
50075 DUK__DUMPSZ(duk_re_token);
50076 DUK__DUMPSZ(duk_lexer_point);
50077 DUK__DUMPSZ(duk_lexer_ctx);
50078 DUK__DUMPSZ(duk_compiler_instr);
50079 DUK__DUMPSZ(duk_compiler_func);
50080 DUK__DUMPSZ(duk_compiler_ctx);
50081 DUK__DUMPSZ(duk_re_matcher_ctx);
50082 DUK__DUMPSZ(duk_re_compiler_ctx);
50083}
50084DUK_LOCAL void duk__dump_type_limits(void) {
50085 DUK_D(DUK_DPRINT("limits"));
50086
50087 /* basic types */
50088 DUK__DUMPLM_SIGNED(INT8);
50089 DUK__DUMPLM_UNSIGNED(UINT8);
50090 DUK__DUMPLM_SIGNED(INT_FAST8);
50091 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
50092 DUK__DUMPLM_SIGNED(INT_LEAST8);
50093 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
50094 DUK__DUMPLM_SIGNED(INT16);
50095 DUK__DUMPLM_UNSIGNED(UINT16);
50096 DUK__DUMPLM_SIGNED(INT_FAST16);
50097 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
50098 DUK__DUMPLM_SIGNED(INT_LEAST16);
50099 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
50100 DUK__DUMPLM_SIGNED(INT32);
50101 DUK__DUMPLM_UNSIGNED(UINT32);
50102 DUK__DUMPLM_SIGNED(INT_FAST32);
50103 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
50104 DUK__DUMPLM_SIGNED(INT_LEAST32);
50105 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
50106#if defined(DUK_USE_64BIT_OPS)
50107 DUK__DUMPLM_SIGNED(INT64);
50108 DUK__DUMPLM_UNSIGNED(UINT64);
50109 DUK__DUMPLM_SIGNED(INT_FAST64);
50110 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
50111 DUK__DUMPLM_SIGNED(INT_LEAST64);
50112 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
50113#endif
50114 DUK__DUMPLM_SIGNED(INTPTR);
50115 DUK__DUMPLM_UNSIGNED(UINTPTR);
50116 DUK__DUMPLM_SIGNED(INTMAX);
50117 DUK__DUMPLM_UNSIGNED(UINTMAX);
50118
50119 /* derived types */
50120 DUK__DUMPLM_SIGNED(INT);
50121 DUK__DUMPLM_UNSIGNED(UINT);
50122 DUK__DUMPLM_SIGNED(INT_FAST);
50123 DUK__DUMPLM_UNSIGNED(UINT_FAST);
50124 DUK__DUMPLM_SIGNED(SMALL_INT);
50125 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
50126 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
50127 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
50128}
50129
50130DUK_LOCAL void duk__dump_misc_options(void) {
50131 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
50132 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
50133 DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
50134 DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
50135 DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
50136 DUK_D(DUK_DPRINT("debug level: %ld", (long) DUK_USE_DEBUG_LEVEL));
50137#if defined(DUK_USE_PACKED_TVAL)
50138 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
50139#else
50140 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
50141#endif
50142#if defined(DUK_USE_VARIADIC_MACROS)
50143 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
50144#else
50145 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
50146#endif
50147#if defined(DUK_USE_INTEGER_LE)
50148 DUK_D(DUK_DPRINT("integer endianness: little"));
50149#elif defined(DUK_USE_INTEGER_ME)
50150 DUK_D(DUK_DPRINT("integer endianness: mixed"));
50151#elif defined(DUK_USE_INTEGER_BE)
50152 DUK_D(DUK_DPRINT("integer endianness: big"));
50153#else
50154 DUK_D(DUK_DPRINT("integer endianness: ???"));
50155#endif
50156#if defined(DUK_USE_DOUBLE_LE)
50157 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
50158#elif defined(DUK_USE_DOUBLE_ME)
50159 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
50160#elif defined(DUK_USE_DOUBLE_BE)
50161 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
50162#else
50163 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
50164#endif
50165}
50166#endif /* DUK_USE_DEBUG */
50167
50168DUK_INTERNAL
50169duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
50170 duk_realloc_function realloc_func,
50171 duk_free_function free_func,
50172 void *heap_udata,
50173 duk_fatal_function fatal_func) {
50174 duk_heap *res = NULL;
50175 duk_uint32_t st_initsize;
50176
50177 DUK_D(DUK_DPRINT("allocate heap"));
50178
50179 /*
50180 * Random config sanity asserts
50181 */
50182
50183 DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64);
50184
50185 DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0);
50186 DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0);
50187 DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */
50188
50189 /*
50190 * Debug dump type sizes
50191 */
50192
50193#if defined(DUK_USE_DEBUG)
50194 duk__dump_misc_options();
50195 duk__dump_type_sizes();
50196 duk__dump_type_limits();
50197#endif
50198
50199 /*
50200 * If selftests enabled, run them as early as possible.
50201 */
50202
50203#if defined(DUK_USE_SELF_TESTS)
50204 DUK_D(DUK_DPRINT("run self tests"));
50205 if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) {
50206 fatal_func(heap_udata, "self test(s) failed");
50207 }
50208 DUK_D(DUK_DPRINT("self tests passed"));
50209#endif
50210
50211 /*
50212 * Important assert-like checks that should be enabled even
50213 * when assertions are otherwise not enabled.
50214 */
50215
50216#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
50217 /* Can't check sizeof() using preprocessor so explicit check.
50218 * This will be optimized away in practice; unfortunately a
50219 * warning is generated on some compilers as a result.
50220 */
50221#if defined(DUK_USE_PACKED_TVAL)
50222 if (sizeof(duk_tval) != 8) {
50223#else
50224 if (sizeof(duk_tval) != 16) {
50225#endif
50226 fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option");
50227 }
50228#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
50229
50230 /*
50231 * Computed values (e.g. INFINITY)
50232 */
50233
50234#if defined(DUK_USE_COMPUTED_NAN)
50235 do {
50236 /* Workaround for some exotic platforms where NAN is missing
50237 * and the expression (0.0 / 0.0) does NOT result in a NaN.
50238 * Such platforms use the global 'duk_computed_nan' which must
50239 * be initialized at runtime. Use 'volatile' to ensure that
50240 * the compiler will actually do the computation and not try
50241 * to do constant folding which might result in the original
50242 * problem.
50243 */
50244 volatile double dbl1 = 0.0;
50245 volatile double dbl2 = 0.0;
50246 duk_computed_nan = dbl1 / dbl2;
50247 } while (0);
50248#endif
50249
50250#if defined(DUK_USE_COMPUTED_INFINITY)
50251 do {
50252 /* Similar workaround for INFINITY. */
50253 volatile double dbl1 = 1.0;
50254 volatile double dbl2 = 0.0;
50255 duk_computed_infinity = dbl1 / dbl2;
50256 } while (0);
50257#endif
50258
50259 /*
50260 * Allocate heap struct
50261 *
50262 * Use a raw call, all macros expect the heap to be initialized
50263 */
50264
50265#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1)
50266 goto failed;
50267#endif
50268 DUK_D(DUK_DPRINT("alloc duk_heap object"));
50269 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
50270 if (!res) {
50271 goto failed;
50272 }
50273
50274 /*
50275 * Zero the struct, and start initializing roughly in order
50276 */
50277
50278 duk_memzero(res, sizeof(*res));
50279#if defined(DUK_USE_ASSERTIONS)
50280 res->heap_initializing = 1;
50281#endif
50282
50283 /* explicit NULL inits */
50284#if defined(DUK_USE_EXPLICIT_NULL_INIT)
50285 res->heap_udata = NULL;
50286 res->heap_allocated = NULL;
50287#if defined(DUK_USE_REFERENCE_COUNTING)
50288 res->refzero_list = NULL;
50289#endif
50290#if defined(DUK_USE_FINALIZER_SUPPORT)
50291 res->finalize_list = NULL;
50292#if defined(DUK_USE_ASSERTIONS)
50293 res->currently_finalizing = NULL;
50294#endif
50295#endif
50296#if defined(DUK_USE_CACHE_ACTIVATION)
50297 res->activation_free = NULL;
50298#endif
50299#if defined(DUK_USE_CACHE_CATCHER)
50300 res->catcher_free = NULL;
50301#endif
50302 res->heap_thread = NULL;
50303 res->curr_thread = NULL;
50304 res->heap_object = NULL;
50305#if defined(DUK_USE_STRTAB_PTRCOMP)
50306 res->strtable16 = NULL;
50307#else
50308 res->strtable = NULL;
50309#endif
50310#if defined(DUK_USE_ROM_STRINGS)
50311 /* no res->strs[] */
50312#else /* DUK_USE_ROM_STRINGS */
50313#if defined(DUK_USE_HEAPPTR16)
50314 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
50315#else
50316 {
50317 duk_small_uint_t i;
50318 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
50319 res->strs[i] = NULL;
50320 }
50321 }
50322#endif
50323#endif /* DUK_USE_ROM_STRINGS */
50324#if defined(DUK_USE_DEBUGGER_SUPPORT)
50325 res->dbg_read_cb = NULL;
50326 res->dbg_write_cb = NULL;
50327 res->dbg_peek_cb = NULL;
50328 res->dbg_read_flush_cb = NULL;
50329 res->dbg_write_flush_cb = NULL;
50330 res->dbg_request_cb = NULL;
50331 res->dbg_udata = NULL;
50332 res->dbg_pause_act = NULL;
50333#endif
50334#endif /* DUK_USE_EXPLICIT_NULL_INIT */
50335
50336 res->alloc_func = alloc_func;
50337 res->realloc_func = realloc_func;
50338 res->free_func = free_func;
50339 res->heap_udata = heap_udata;
50340 res->fatal_func = fatal_func;
50341
50342 /* XXX: for now there's a pointer packing zero assumption, i.e.
50343 * NULL <=> compressed pointer 0. If this is removed, may need
50344 * to precompute e.g. null16 here.
50345 */
50346
50347 /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */
50348
50349 /* Prevent mark-and-sweep and finalizer execution until heap is completely
50350 * initialized.
50351 */
50352 DUK_ASSERT(res->ms_prevent_count == 0);
50353 DUK_ASSERT(res->pf_prevent_count == 0);
50354 res->ms_prevent_count = 1;
50355 res->pf_prevent_count = 1;
50356 DUK_ASSERT(res->ms_running == 0);
50357
50358 res->call_recursion_depth = 0;
50359 res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
50360
50361 /* XXX: use the pointer as a seed for now: mix in time at least */
50362
50363 /* The casts through duk_uintptr_t is to avoid the following GCC warning:
50364 *
50365 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
50366 *
50367 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
50368 */
50369#if defined(DUK_USE_ROM_STRINGS)
50370 /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
50371 DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
50372 res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
50373#else /* DUK_USE_ROM_STRINGS */
50374 res->hash_seed = (duk_uint32_t) (duk_uintptr_t) res;
50375#if !defined(DUK_USE_STRHASH_DENSE)
50376 res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
50377#endif
50378#endif /* DUK_USE_ROM_STRINGS */
50379
50380#if defined(DUK_USE_EXPLICIT_NULL_INIT)
50381 res->lj.jmpbuf_ptr = NULL;
50382#endif
50383 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
50384 DUK_ASSERT(res->lj.iserror == 0);
50385 DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
50386 DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
50387
50388 DUK_ASSERT_LJSTATE_UNSET(res);
50389
50390 /*
50391 * Init stringtable: fixed variant
50392 */
50393
50394 st_initsize = DUK_USE_STRTAB_MINSIZE;
50395#if defined(DUK_USE_STRTAB_PTRCOMP)
50396 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize);
50397 if (res->strtable16 == NULL) {
50398 goto failed;
50399 }
50400#else
50401 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize);
50402 if (res->strtable == NULL) {
50403 goto failed;
50404 }
50405#endif
50406 res->st_size = st_initsize;
50407 res->st_mask = st_initsize - 1;
50408#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
50409 DUK_ASSERT(res->st_count == 0);
50410#endif
50411
50412#if defined(DUK_USE_STRTAB_PTRCOMP)
50413 /* zero assumption */
50414 duk_memzero(res->strtable16, sizeof(duk_uint16_t) * st_initsize);
50415#else
50416#if defined(DUK_USE_EXPLICIT_NULL_INIT)
50417 {
50418 duk_uint32_t i;
50419 for (i = 0; i < st_initsize; i++) {
50420 res->strtable[i] = NULL;
50421 }
50422 }
50423#else
50424 duk_memzero(res->strtable, sizeof(duk_hstring *) * st_initsize);
50425#endif /* DUK_USE_EXPLICIT_NULL_INIT */
50426#endif /* DUK_USE_STRTAB_PTRCOMP */
50427
50428 /*
50429 * Init stringcache
50430 */
50431
50432#if defined(DUK_USE_EXPLICIT_NULL_INIT)
50433 {
50434 duk_uint_t i;
50435 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
50436 res->strcache[i].h = NULL;
50437 }
50438 }
50439#endif
50440
50441 /*
50442 * Init litcache
50443 */
50444#if defined(DUK_USE_LITCACHE_SIZE)
50445 DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
50446 DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
50447#if defined(DUK_USE_EXPLICIT_NULL_INIT)
50448 {
50449 duk_uint_t i;
50450 for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
50451 res->litcache[i].addr = NULL;
50452 res->litcache[i].h = NULL;
50453 }
50454 }
50455#endif
50456#endif /* DUK_USE_LITCACHE_SIZE */
50457
50458 /* XXX: error handling is incomplete. It would be cleanest if
50459 * there was a setjmp catchpoint, so that all init code could
50460 * freely throw errors. If that were the case, the return code
50461 * passing here could be removed.
50462 */
50463
50464 /*
50465 * Init built-in strings
50466 */
50467
50468#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2)
50469 goto failed;
50470#endif
50471 DUK_D(DUK_DPRINT("heap init: initialize heap strings"));
50472 if (!duk__init_heap_strings(res)) {
50473 goto failed;
50474 }
50475
50476 /*
50477 * Init the heap thread
50478 */
50479
50480#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3)
50481 goto failed;
50482#endif
50483 DUK_D(DUK_DPRINT("heap init: initialize heap thread"));
50484 if (!duk__init_heap_thread(res)) {
50485 goto failed;
50486 }
50487
50488 /*
50489 * Init the heap object
50490 */
50491
50492#if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4)
50493 goto failed;
50494#endif
50495 DUK_D(DUK_DPRINT("heap init: initialize heap object"));
50496 DUK_ASSERT(res->heap_thread != NULL);
50497 res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
50498 DUK_HOBJECT_FLAG_FASTREFS |
50499 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
50500 if (res->heap_object == NULL) {
50501 goto failed;
50502 }
50503 DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
50504
50505 /*
50506 * Odds and ends depending on the heap thread
50507 */
50508
50509#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
50510#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
50511 res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread);
50512 duk_util_tinyrandom_prepare_seed(res->heap_thread);
50513#else
50514 res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread);
50515 DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */
50516#if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */
50517 res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678);
50518 res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678);
50519#endif
50520 duk_util_tinyrandom_prepare_seed(res->heap_thread);
50521 /* Mix in heap pointer: this ensures that if two Duktape heaps are
50522 * created on the same millisecond, they get a different PRNG
50523 * sequence (unless e.g. virtual memory addresses cause also the
50524 * heap object pointer to be the same).
50525 */
50526 {
50527 duk_uint64_t tmp_u64;
50528 tmp_u64 = 0;
50529 duk_memcpy((void *) &tmp_u64,
50530 (const void *) &res,
50531 (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *)));
50532 res->rnd_state[1] ^= tmp_u64;
50533 }
50534 do {
50535 duk_small_uint_t i;
50536 for (i = 0; i < 10; i++) {
50537 /* Throw away a few initial random numbers just in
50538 * case. Probably unnecessary due to SplitMix64
50539 * preparation.
50540 */
50541 (void) duk_util_tinyrandom_get_double(res->heap_thread);
50542 }
50543 } while (0);
50544#endif
50545#endif
50546
50547 /*
50548 * Allow finalizer and mark-and-sweep processing.
50549 */
50550
50551 DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing"));
50552 DUK_ASSERT(res->ms_prevent_count == 1);
50553 DUK_ASSERT(res->pf_prevent_count == 1);
50554 res->ms_prevent_count = 0;
50555 res->pf_prevent_count = 0;
50556 DUK_ASSERT(res->ms_running == 0);
50557#if defined(DUK_USE_ASSERTIONS)
50558 res->heap_initializing = 0;
50559#endif
50560
50561 /*
50562 * All done.
50563 */
50564
50565 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
50566 return res;
50567
50568 failed:
50569 DUK_D(DUK_DPRINT("heap allocation failed"));
50570
50571 if (res != NULL) {
50572 /* Assumes that allocated pointers and alloc funcs are valid
50573 * if res exists.
50574 */
50575 DUK_ASSERT(res->ms_prevent_count == 1);
50576 DUK_ASSERT(res->pf_prevent_count == 1);
50577 DUK_ASSERT(res->ms_running == 0);
50578 if (res->heap_thread != NULL) {
50579 res->ms_prevent_count = 0;
50580 res->pf_prevent_count = 0;
50581 }
50582#if defined(DUK_USE_ASSERTIONS)
50583 res->heap_initializing = 0;
50584#endif
50585
50586 DUK_ASSERT(res->alloc_func != NULL);
50587 DUK_ASSERT(res->realloc_func != NULL);
50588 DUK_ASSERT(res->free_func != NULL);
50589 duk_heap_free(res);
50590 }
50591
50592 return NULL;
50593}
50594
50595/* automatic undefs */
50596#undef DUK__DUMPLM_SIGNED
50597#undef DUK__DUMPLM_SIGNED_RAW
50598#undef DUK__DUMPLM_UNSIGNED
50599#undef DUK__DUMPLM_UNSIGNED_RAW
50600#undef DUK__DUMPSZ
50601#undef DUK__FIXED_HASH_SEED
50602#line 1 "duk_heap_finalize.c"
50603/*
50604 * Finalizer handling.
50605 */
50606
50607/* #include duk_internal.h -> already included */
50608
50609#if defined(DUK_USE_FINALIZER_SUPPORT)
50610
50611/*
50612 * Fake torture finalizer.
50613 */
50614
50615#if defined(DUK_USE_FINALIZER_TORTURE)
50616DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) {
50617 DUK_DD(DUK_DDPRINT("fake global torture finalizer executed"));
50618
50619 /* Require a lot of stack to force a value stack grow/shrink. */
50620 duk_require_stack(thr, 100000);
50621
50622 /* Force a reallocation with pointer change for value stack
50623 * to maximize side effects.
50624 */
50625 duk_hthread_valstack_torture_realloc(thr);
50626
50627 /* Inner function call, error throw. */
50628 duk_eval_string_noresult(thr,
50629 "(function dummy() {\n"
50630 " dummy.prototype = null; /* break reference loop */\n"
50631 " try {\n"
50632 " throw 'fake-finalizer-dummy-error';\n"
50633 " } catch (e) {\n"
50634 " void e;\n"
50635 " }\n"
50636 "})()");
50637
50638 /* The above creates garbage (e.g. a function instance). Because
50639 * the function/prototype reference loop is broken, it gets collected
50640 * immediately by DECREF. If Function.prototype has a _Finalizer
50641 * property (happens in some test cases), the garbage gets queued to
50642 * finalize_list. This still won't cause an infinite loop because
50643 * the torture finalizer is called once per finalize_list run and
50644 * the garbage gets handled in the same run. (If the garbage needs
50645 * mark-and-sweep collection, an infinite loop might ensue.)
50646 */
50647 return 0;
50648}
50649
50650DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) {
50651 DUK_ASSERT(thr != NULL);
50652
50653 /* Avoid fake finalization when callstack limit is near. Otherwise
50654 * a callstack limit error will be created, then refzero'ed. The
50655 * +5 headroom is conservative.
50656 */
50657 if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit ||
50658 thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) {
50659 DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size"));
50660 return;
50661 }
50662
50663 /* Run fake finalizer. Avoid creating unnecessary garbage. */
50664 duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/);
50665 (void) duk_pcall(thr, 0 /*nargs*/);
50666 duk_pop(thr);
50667}
50668#endif /* DUK_USE_FINALIZER_TORTURE */
50669
50670/*
50671 * Process the finalize_list to completion.
50672 *
50673 * An object may be placed on finalize_list by either refcounting or
50674 * mark-and-sweep. The refcount of objects placed by refcounting will be
50675 * zero; the refcount of objects placed by mark-and-sweep is > 0. In both
50676 * cases the refcount is bumped by 1 artificially so that a REFZERO event
50677 * can never happen while an object is waiting for finalization. Without
50678 * this bump a REFZERO could now happen because user code may call
50679 * duk_push_heapptr() and then pop a value even when it's on finalize_list.
50680 *
50681 * List processing assumes refcounts are kept up-to-date at all times, so
50682 * that once the finalizer returns, a zero refcount is a reliable reason to
50683 * free the object immediately rather than place it back to the heap. This
50684 * is the case because we run outside of refzero_list processing so that
50685 * DECREF cascades are handled fully inline.
50686 *
50687 * For mark-and-sweep queued objects (had_zero_refcount false) the object
50688 * may be freed immediately if its refcount is zero after the finalizer call
50689 * (i.e. finalizer removed the reference loop for the object). If not, the
50690 * next mark-and-sweep will collect the object unless it has become reachable
50691 * (i.e. rescued) by that time and its refcount hasn't fallen to zero before
50692 * that. Mark-and-sweep detects these objects because their FINALIZED flag
50693 * is set.
50694 *
50695 * There's an inherent limitation for mark-and-sweep finalizer rescuing: an
50696 * object won't get refinalized if (1) it's rescued, but (2) becomes
50697 * unreachable before mark-and-sweep has had time to notice it. The next
50698 * mark-and-sweep round simply doesn't have any information of whether the
50699 * object has been unreachable the whole time or not (the only way to get
50700 * that information would be a mark-and-sweep pass for *every finalized
50701 * object*). This is awkward for the application because the mark-and-sweep
50702 * round is not generally visible or under full application control.
50703 *
50704 * For refcount queued objects (had_zero_refcount true) the object is either
50705 * immediately freed or rescued, and waiting for a mark-and-sweep round is not
50706 * necessary (or desirable); FINALIZED is cleared when a rescued object is
50707 * queued back to heap_allocated. The object is eligible for finalization
50708 * again (either via refcounting or mark-and-sweep) immediately after being
50709 * rescued. If a refcount finalized object is placed into an unreachable
50710 * reference loop by its finalizer, it will get collected by mark-and-sweep
50711 * and currently the finalizer will execute again.
50712 *
50713 * There's a special case where:
50714 *
50715 * - Mark-and-sweep queues an object to finalize_list for finalization.
50716 * - The finalizer is executed, FINALIZED is set, and object is queued
50717 * back to heap_allocated, waiting for a new mark-and-sweep round.
50718 * - The object's refcount drops to zero before mark-and-sweep has a
50719 * chance to run another round and make a rescue/free decision.
50720 *
50721 * This is now handled by refzero code: if an object has a finalizer but
50722 * FINALIZED is already set, the object is freed without finalizer processing.
50723 * The outcome is the same as if mark-and-sweep was executed at that point;
50724 * mark-and-sweep would also free the object without another finalizer run.
50725 * This could also be changed so that the refzero-triggered finalizer *IS*
50726 * executed: being refzero collected implies someone has operated on the
50727 * object so it hasn't been totally unreachable the whole time. This would
50728 * risk a finalizer loop however.
50729 */
50730
50731DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
50732 duk_heaphdr *curr;
50733#if defined(DUK_USE_DEBUG)
50734 duk_size_t count = 0;
50735#endif
50736
50737 DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p", (void *) heap));
50738
50739 if (heap->pf_prevent_count != 0) {
50740 DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0"));
50741 return;
50742 }
50743
50744 /* Heap alloc prevents mark-and-sweep before heap_thread is ready. */
50745 DUK_ASSERT(heap != NULL);
50746 DUK_ASSERT(heap->heap_thread != NULL);
50747 DUK_ASSERT(heap->heap_thread->valstack != NULL);
50748#if defined(DUK_USE_REFERENCE_COUNTING)
50749 DUK_ASSERT(heap->refzero_list == NULL);
50750#endif
50751
50752 DUK_ASSERT(heap->pf_prevent_count == 0);
50753 heap->pf_prevent_count = 1;
50754
50755 /* Mark-and-sweep no longer needs to be prevented when running
50756 * finalizers: mark-and-sweep skips any rescue decisions if there
50757 * are any objects in finalize_list when mark-and-sweep is entered.
50758 * This protects finalized objects from incorrect rescue decisions
50759 * caused by finalize_list being a reachability root and only
50760 * partially processed. Freeing decisions are not postponed.
50761 */
50762
50763 /* When finalizer torture is enabled, make a fake finalizer call with
50764 * maximum side effects regardless of whether finalize_list is empty.
50765 */
50766#if defined(DUK_USE_FINALIZER_TORTURE)
50767 duk__run_global_torture_finalizer(heap->heap_thread);
50768#endif
50769
50770 /* Process finalize_list until it becomes empty. There's currently no
50771 * protection against a finalizer always creating more garbage.
50772 */
50773 while ((curr = heap->finalize_list) != NULL) {
50774#if defined(DUK_USE_REFERENCE_COUNTING)
50775 duk_bool_t queue_back;
50776#endif
50777
50778 DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO", (void *) curr, curr));
50779
50780 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* Only objects have finalizers. */
50781 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
50782 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
50783 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); /* All objects on finalize_list will have this flag (except object being finalized right now). */
50784 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); /* Queueing code ensures. */
50785 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* ROM objects never get freed (or finalized). */
50786
50787#if defined(DUK_USE_ASSERTIONS)
50788 DUK_ASSERT(heap->currently_finalizing == NULL);
50789 heap->currently_finalizing = curr;
50790#endif
50791
50792 /* Clear FINALIZABLE for object being finalized, so that
50793 * duk_push_heapptr() can properly ignore the object.
50794 */
50795 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
50796
50797 if (DUK_LIKELY(!heap->pf_skip_finalizers)) {
50798 /* Run the finalizer, duk_heap_run_finalizer() sets
50799 * and checks for FINALIZED to prevent the finalizer
50800 * from executing multiple times per finalization cycle.
50801 * (This safeguard shouldn't be actually needed anymore).
50802 */
50803
50804#if defined(DUK_USE_REFERENCE_COUNTING)
50805 duk_bool_t had_zero_refcount;
50806#endif
50807
50808 /* The object's refcount is >0 throughout so it won't be
50809 * refzero processed prematurely.
50810 */
50811#if defined(DUK_USE_REFERENCE_COUNTING)
50812 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
50813 had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1); /* Preincremented on finalize_list insert. */
50814#endif
50815
50816 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
50817 duk_heap_run_finalizer(heap, (duk_hobject *) curr); /* must never longjmp */
50818 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
50819 /* XXX: assert that object is still in finalize_list
50820 * when duk_push_heapptr() allows automatic rescue.
50821 */
50822
50823#if defined(DUK_USE_REFERENCE_COUNTING)
50824 DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld", (long) DUK_HEAPHDR_GET_REFCOUNT(curr)));
50825 if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) { /* Only artificial bump in refcount? */
50826#if defined(DUK_USE_DEBUG)
50827 if (had_zero_refcount) {
50828 DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)"));
50829 } else {
50830 DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)"));
50831 }
50832#endif
50833 queue_back = 0;
50834 } else
50835#endif
50836 {
50837#if defined(DUK_USE_REFERENCE_COUNTING)
50838 queue_back = 1;
50839 if (had_zero_refcount) {
50840 /* When finalization is triggered
50841 * by refzero and we queue the object
50842 * back, clear FINALIZED right away
50843 * so that the object can be refinalized
50844 * immediately if necessary.
50845 */
50846 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
50847 }
50848#endif
50849 }
50850 } else {
50851 /* Used during heap destruction: don't actually run finalizers
50852 * because we're heading into forced finalization. Instead,
50853 * queue finalizable objects back to the heap_allocated list.
50854 */
50855 DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
50856 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
50857#if defined(DUK_USE_REFERENCE_COUNTING)
50858 queue_back = 1;
50859#endif
50860 }
50861
50862 /* Dequeue object from finalize_list. Note that 'curr' may no
50863 * longer be finalize_list head because new objects may have
50864 * been queued to the list. As a result we can't optimize for
50865 * the single-linked heap case and must scan the list for
50866 * removal, typically the scan is very short however.
50867 */
50868 DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr);
50869
50870 /* Queue back to heap_allocated or free immediately. */
50871#if defined(DUK_USE_REFERENCE_COUNTING)
50872 if (queue_back) {
50873 /* FINALIZED is only cleared if object originally
50874 * queued for finalization by refcounting. For
50875 * mark-and-sweep FINALIZED is left set, so that
50876 * next mark-and-sweep round can make a rescue/free
50877 * decision.
50878 */
50879 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
50880 DUK_HEAPHDR_PREDEC_REFCOUNT(curr); /* Remove artificial refcount bump. */
50881 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
50882 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
50883 } else {
50884 /* No need to remove the refcount bump here. */
50885 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
50886 DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O", curr));
50887 duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
50888 duk_free_hobject(heap, (duk_hobject *) curr);
50889 DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p", (void *) curr));
50890 }
50891#else /* DUK_USE_REFERENCE_COUNTING */
50892 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
50893 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
50894#endif /* DUK_USE_REFERENCE_COUNTING */
50895
50896#if defined(DUK_USE_DEBUG)
50897 count++;
50898#endif
50899
50900#if defined(DUK_USE_ASSERTIONS)
50901 DUK_ASSERT(heap->currently_finalizing != NULL);
50902 heap->currently_finalizing = NULL;
50903#endif
50904 }
50905
50906 /* finalize_list will always be processed completely. */
50907 DUK_ASSERT(heap->finalize_list == NULL);
50908
50909#if 0
50910 /* While NORZ macros are used above, this is unnecessary because the
50911 * only pending side effects are now finalizers, and finalize_list is
50912 * empty.
50913 */
50914 DUK_REFZERO_CHECK_SLOW(heap->heap_thread);
50915#endif
50916
50917 /* Prevent count may be bumped while finalizers run, but should always
50918 * be reliably unbumped by the time we get here.
50919 */
50920 DUK_ASSERT(heap->pf_prevent_count == 1);
50921 heap->pf_prevent_count = 0;
50922
50923#if defined(DUK_USE_DEBUG)
50924 DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called", (long) count));
50925#endif
50926}
50927
50928/*
50929 * Run an duk_hobject finalizer. Must never throw an uncaught error
50930 * (but may throw caught errors).
50931 *
50932 * There is no return value. Any return value or error thrown by
50933 * the finalizer is ignored (although errors are debug logged).
50934 *
50935 * Notes:
50936 *
50937 * - The finalizer thread 'top' assertions are there because it is
50938 * critical that strict stack policy is observed (i.e. no cruft
50939 * left on the finalizer stack).
50940 */
50941
50942DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) {
50943 DUK_ASSERT(thr != NULL);
50944 DUK_UNREF(udata);
50945
50946 DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
50947
50948 /* [... obj] */
50949
50950 /* _Finalizer property is read without checking if the value is
50951 * callable or even exists. This is intentional, and handled
50952 * by throwing an error which is caught by the safe call wrapper.
50953 *
50954 * XXX: Finalizer lookup should traverse the prototype chain (to allow
50955 * inherited finalizers) but should not invoke accessors or proxy object
50956 * behavior. At the moment this lookup will invoke proxy behavior, so
50957 * caller must ensure that this function is not called if the target is
50958 * a Proxy.
50959 */
50960 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
50961 duk_dup_m2(thr);
50962 duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
50963 DUK_DDD(DUK_DDDPRINT("calling finalizer"));
50964 duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
50965 DUK_DDD(DUK_DDDPRINT("finalizer returned successfully"));
50966 return 0;
50967
50968 /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
50969 * so we don't need to pop stuff here. There is no return value;
50970 * caller determines rescued status based on object refcount.
50971 */
50972}
50973
50974DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
50975 duk_hthread *thr;
50976 duk_ret_t rc;
50977#if defined(DUK_USE_ASSERTIONS)
50978 duk_idx_t entry_top;
50979#endif
50980
50981 DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p", (void *) obj));
50982
50983 DUK_ASSERT(heap != NULL);
50984 DUK_ASSERT(heap->heap_thread != NULL);
50985 thr = heap->heap_thread;
50986 DUK_ASSERT(obj != NULL);
50987 DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1);
50988
50989#if defined(DUK_USE_ASSERTIONS)
50990 entry_top = duk_get_top(thr);
50991#endif
50992 /*
50993 * Get and call the finalizer. All of this must be wrapped
50994 * in a protected call, because even getting the finalizer
50995 * may trigger an error (getter may throw one, for instance).
50996 */
50997
50998 /* ROM objects could inherit a finalizer, but they are never deemed
50999 * unreachable by mark-and-sweep, and their refcount never falls to 0.
51000 */
51001 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
51002
51003 /* Duktape 2.1: finalize_list never contains objects with FINALIZED
51004 * set, so no need to check here.
51005 */
51006 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj));
51007#if 0
51008 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
51009 DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
51010 return;
51011 }
51012#endif
51013 DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
51014
51015#if defined(DUK_USE_ES6_PROXY)
51016 if (DUK_HOBJECT_IS_PROXY(obj)) {
51017 /* This may happen if duk_set_finalizer() or Duktape.fin() is
51018 * called for a Proxy object. In such cases the fast finalizer
51019 * flag will be set on the Proxy, not the target, and neither
51020 * will be finalized.
51021 */
51022 DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call"));
51023 return;
51024 }
51025#endif /* DUK_USE_ES6_PROXY */
51026
51027 duk_push_hobject(thr, obj); /* this also increases refcount by one */
51028 rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
51029 DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */
51030
51031 if (rc != DUK_EXEC_SUCCESS) {
51032 /* Note: we ask for one return value from duk_safe_call to get this
51033 * error debugging here.
51034 */
51035 DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
51036 (void *) obj, (duk_tval *) duk_get_tval(thr, -1)));
51037 }
51038 duk_pop_2(thr); /* -> [...] */
51039
51040 DUK_ASSERT_TOP(thr, entry_top);
51041}
51042
51043#else /* DUK_USE_FINALIZER_SUPPORT */
51044
51045/* nothing */
51046
51047#endif /* DUK_USE_FINALIZER_SUPPORT */
51048#line 1 "duk_heap_hashstring.c"
51049/*
51050 * String hash computation (interning).
51051 *
51052 * String hashing is performance critical because a string hash is computed
51053 * for all new strings which are candidates to be added to the string table.
51054 * However, strings actually added to the string table go through a codepoint
51055 * length calculation which dominates performance because it goes through
51056 * every byte of the input string (but only for strings added).
51057 *
51058 * The string hash algorithm should be fast, but on the other hand provide
51059 * good enough hashes to ensure both string table and object property table
51060 * hash tables work reasonably well (i.e., there aren't too many collisions
51061 * with real world inputs). Unless the hash is cryptographic, it's always
51062 * possible to craft inputs with maximal hash collisions.
51063 *
51064 * NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring()
51065 * for ROM string support!
51066 */
51067
51068/* #include duk_internal.h -> already included */
51069
51070#if defined(DUK_USE_STRHASH_DENSE)
51071/* Constants for duk_hashstring(). */
51072#define DUK__STRHASH_SHORTSTRING 4096L
51073#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
51074#define DUK__STRHASH_BLOCKSIZE 256L
51075
51076DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
51077 duk_uint32_t hash;
51078
51079 /* Use Murmurhash2 directly for short strings, and use "block skipping"
51080 * for long strings: hash an initial part and then sample the rest of
51081 * the string with reasonably sized chunks. An initial offset for the
51082 * sampling is computed based on a hash of the initial part of the string;
51083 * this is done to (usually) avoid the case where all long strings have
51084 * certain offset ranges which are never sampled.
51085 *
51086 * Skip should depend on length and bound the total time to roughly
51087 * logarithmic. With current values:
51088 *
51089 * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
51090 * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
51091 *
51092 * XXX: It would be better to compute the skip offset more "smoothly"
51093 * instead of having a few boundary values.
51094 */
51095
51096 /* note: mixing len into seed improves hashing when skipping */
51097 duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
51098
51099 if (len <= DUK__STRHASH_SHORTSTRING) {
51100 hash = duk_util_hashbytes(str, len, str_seed);
51101 } else {
51102 duk_size_t off;
51103 duk_size_t skip;
51104
51105 if (len <= DUK__STRHASH_MEDIUMSTRING) {
51106 skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
51107 } else {
51108 skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
51109 }
51110
51111 hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
51112 off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
51113
51114 /* XXX: inefficient loop */
51115 while (off < len) {
51116 duk_size_t left = len - off;
51117 duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
51118 hash ^= duk_util_hashbytes(str + off, now, str_seed);
51119 off += skip;
51120 }
51121 }
51122
51123#if defined(DUK_USE_STRHASH16)
51124 /* Truncate to 16 bits here, so that a computed hash can be compared
51125 * against a hash stored in a 16-bit field.
51126 */
51127 hash &= 0x0000ffffUL;
51128#endif
51129 return hash;
51130}
51131#else /* DUK_USE_STRHASH_DENSE */
51132DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
51133 duk_uint32_t hash;
51134 duk_size_t step;
51135 duk_size_t off;
51136
51137 /* Slightly modified "Bernstein hash" from:
51138 *
51139 * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
51140 *
51141 * Modifications: string skipping and reverse direction similar to
51142 * Lua 5.1.5, and different hash initializer.
51143 *
51144 * The reverse direction ensures last byte it always included in the
51145 * hash which is a good default as changing parts of the string are
51146 * more often in the suffix than in the prefix.
51147 */
51148
51149 hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
51150 step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
51151 for (off = len; off >= step; off -= step) {
51152 DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
51153 hash = (hash * 33) + str[off - 1];
51154 }
51155
51156#if defined(DUK_USE_STRHASH16)
51157 /* Truncate to 16 bits here, so that a computed hash can be compared
51158 * against a hash stored in a 16-bit field.
51159 */
51160 hash &= 0x0000ffffUL;
51161#endif
51162 return hash;
51163}
51164#endif /* DUK_USE_STRHASH_DENSE */
51165
51166/* automatic undefs */
51167#undef DUK__STRHASH_BLOCKSIZE
51168#undef DUK__STRHASH_MEDIUMSTRING
51169#undef DUK__STRHASH_SHORTSTRING
51170#line 1 "duk_heap_markandsweep.c"
51171/*
51172 * Mark-and-sweep garbage collection.
51173 */
51174
51175/* #include duk_internal.h -> already included */
51176
51177DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
51178DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h);
51179DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
51180DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count);
51181
51182/*
51183 * Marking functions for heap types: mark children recursively.
51184 */
51185
51186DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
51187 DUK_UNREF(heap);
51188 DUK_UNREF(h);
51189
51190 DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
51191 DUK_ASSERT(h);
51192 DUK_HSTRING_ASSERT_VALID(h);
51193
51194 /* nothing to process */
51195}
51196
51197DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
51198 duk_uint_fast32_t i;
51199
51200 DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
51201
51202 DUK_ASSERT(h);
51203 DUK_HOBJECT_ASSERT_VALID(h);
51204
51205 /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
51206
51207 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
51208 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
51209 if (key == NULL) {
51210 continue;
51211 }
51212 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key);
51213 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
51214 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
51215 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
51216 } else {
51217 duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
51218 }
51219 }
51220
51221 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
51222 duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
51223 }
51224
51225 /* Hash part is a 'weak reference' and does not contribute. */
51226
51227 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
51228
51229 /* Fast path for objects which don't have a subclass struct, or have a
51230 * subclass struct but nothing that needs marking in the subclass struct.
51231 */
51232 if (DUK_HOBJECT_HAS_FASTREFS(h)) {
51233 DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
51234 return;
51235 }
51236 DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
51237
51238 /* XXX: reorg, more common first */
51239 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
51240 duk_hcompfunc *f = (duk_hcompfunc *) h;
51241 duk_tval *tv, *tv_end;
51242 duk_hobject **fn, **fn_end;
51243
51244 DUK_HCOMPFUNC_ASSERT_VALID(f);
51245
51246 /* 'data' is reachable through every compiled function which
51247 * contains a reference.
51248 */
51249
51250 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f));
51251 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
51252 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
51253
51254 if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) {
51255 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
51256 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
51257 while (tv < tv_end) {
51258 duk__mark_tval(heap, tv);
51259 tv++;
51260 }
51261
51262 fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
51263 fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
51264 while (fn < fn_end) {
51265 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn);
51266 fn++;
51267 }
51268 } else {
51269 /* May happen in some out-of-memory corner cases. */
51270 DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking"));
51271 }
51272 } else if (DUK_HOBJECT_IS_DECENV(h)) {
51273 duk_hdecenv *e = (duk_hdecenv *) h;
51274 DUK_HDECENV_ASSERT_VALID(e);
51275 duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread);
51276 duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap);
51277 } else if (DUK_HOBJECT_IS_OBJENV(h)) {
51278 duk_hobjenv *e = (duk_hobjenv *) h;
51279 DUK_HOBJENV_ASSERT_VALID(e);
51280 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target);
51281#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
51282 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
51283 duk_hbufobj *b = (duk_hbufobj *) h;
51284 DUK_HBUFOBJ_ASSERT_VALID(b);
51285 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
51286 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
51287#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
51288 } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
51289 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
51290 DUK_HBOUNDFUNC_ASSERT_VALID(f);
51291 duk__mark_tval(heap, &f->target);
51292 duk__mark_tval(heap, &f->this_binding);
51293 duk__mark_tvals(heap, f->args, f->nargs);
51294#if defined(DUK_USE_ES6_PROXY)
51295 } else if (DUK_HOBJECT_IS_PROXY(h)) {
51296 duk_hproxy *p = (duk_hproxy *) h;
51297 DUK_HPROXY_ASSERT_VALID(p);
51298 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target);
51299 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler);
51300#endif /* DUK_USE_ES6_PROXY */
51301 } else if (DUK_HOBJECT_IS_THREAD(h)) {
51302 duk_hthread *t = (duk_hthread *) h;
51303 duk_activation *act;
51304 duk_tval *tv;
51305
51306 DUK_HTHREAD_ASSERT_VALID(t);
51307
51308 tv = t->valstack;
51309 while (tv < t->valstack_top) {
51310 duk__mark_tval(heap, tv);
51311 tv++;
51312 }
51313
51314 for (act = t->callstack_curr; act != NULL; act = act->parent) {
51315 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
51316 duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
51317 duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
51318#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
51319 duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
51320#endif
51321#if 0 /* nothing now */
51322 for (cat = act->cat; cat != NULL; cat = cat->parent) {
51323 }
51324#endif
51325 }
51326
51327 duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
51328
51329 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
51330 duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
51331 }
51332 } else {
51333 /* We may come here if the object should have a FASTREFS flag
51334 * but it's missing for some reason. Assert for never getting
51335 * here; however, other than performance, this is harmless.
51336 */
51337 DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
51338 DUK_ASSERT(0);
51339 }
51340}
51341
51342/* Mark any duk_heaphdr type. Recursion tracking happens only here. */
51343DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
51344 DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
51345 (void *) h,
51346 (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
51347
51348 /* XXX: add non-null variant? */
51349 if (h == NULL) {
51350 return;
51351 }
51352
51353 DUK_HEAPHDR_ASSERT_VALID(h);
51354 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h));
51355
51356#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
51357 if (!DUK_HEAPHDR_HAS_READONLY(h)) {
51358 h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */
51359 }
51360#endif
51361 if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
51362 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
51363 return;
51364 }
51365#if defined(DUK_USE_ROM_OBJECTS)
51366 /* READONLY objects always have REACHABLE set, so the check above
51367 * will prevent READONLY objects from being marked here.
51368 */
51369 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h));
51370#endif
51371
51372 DUK_HEAPHDR_SET_REACHABLE(h);
51373
51374 if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
51375 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
51376 DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
51377 DUK_HEAPHDR_SET_TEMPROOT(h);
51378 return;
51379 }
51380
51381 heap->ms_recursion_depth++;
51382 DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */
51383
51384 switch (DUK_HEAPHDR_GET_TYPE(h)) {
51385 case DUK_HTYPE_STRING:
51386 duk__mark_hstring(heap, (duk_hstring *) h);
51387 break;
51388 case DUK_HTYPE_OBJECT:
51389 duk__mark_hobject(heap, (duk_hobject *) h);
51390 break;
51391 case DUK_HTYPE_BUFFER:
51392 /* nothing to mark */
51393 break;
51394 default:
51395 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
51396 DUK_UNREACHABLE();
51397 }
51398
51399 DUK_ASSERT(heap->ms_recursion_depth > 0);
51400 heap->ms_recursion_depth--;
51401}
51402
51403DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
51404 DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
51405 if (tv == NULL) {
51406 return;
51407 }
51408 DUK_TVAL_ASSERT_VALID(tv);
51409 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
51410 duk_heaphdr *h;
51411 h = DUK_TVAL_GET_HEAPHDR(tv);
51412 DUK_ASSERT(h != NULL);
51413 duk__mark_heaphdr_nonnull(heap, h);
51414 }
51415}
51416
51417DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) {
51418 DUK_ASSERT(count == 0 || tv != NULL);
51419
51420 while (count-- > 0) {
51421 DUK_TVAL_ASSERT_VALID(tv);
51422 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
51423 duk_heaphdr *h;
51424 h = DUK_TVAL_GET_HEAPHDR(tv);
51425 DUK_ASSERT(h != NULL);
51426 duk__mark_heaphdr_nonnull(heap, h);
51427 }
51428 tv++;
51429 }
51430}
51431
51432/* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */
51433DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) {
51434 /* For now, just call the generic handler. Change when call sites
51435 * are changed too.
51436 */
51437 duk__mark_heaphdr(heap, h);
51438}
51439
51440/*
51441 * Mark the heap.
51442 */
51443
51444DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
51445 duk_small_uint_t i;
51446
51447 DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
51448
51449 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
51450 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
51451
51452 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
51453 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
51454 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
51455 }
51456
51457 duk__mark_tval(heap, &heap->lj.value1);
51458 duk__mark_tval(heap, &heap->lj.value2);
51459
51460#if defined(DUK_USE_DEBUGGER_SUPPORT)
51461 for (i = 0; i < heap->dbg_breakpoint_count; i++) {
51462 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
51463 }
51464#endif
51465}
51466
51467/*
51468 * Mark unreachable, finalizable objects.
51469 *
51470 * Such objects will be moved aside and their finalizers run later. They
51471 * have to be treated as reachability roots for their properties etc to
51472 * remain allocated. This marking is only done for unreachable values which
51473 * would be swept later.
51474 *
51475 * Objects are first marked FINALIZABLE and only then marked as reachability
51476 * roots; otherwise circular references might be handled inconsistently.
51477 */
51478
51479#if defined(DUK_USE_FINALIZER_SUPPORT)
51480DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
51481 duk_heaphdr *hdr;
51482 duk_size_t count_finalizable = 0;
51483
51484 DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
51485
51486 DUK_ASSERT(heap->heap_thread != NULL);
51487
51488 hdr = heap->heap_allocated;
51489 while (hdr != NULL) {
51490 /* A finalizer is looked up from the object and up its
51491 * prototype chain (which allows inherited finalizers).
51492 * The finalizer is checked for using a duk_hobject flag
51493 * which is kept in sync with the presence and callability
51494 * of a _Finalizer hidden symbol.
51495 */
51496
51497 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
51498 DUK_HEAPHDR_IS_OBJECT(hdr) &&
51499 !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
51500 DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) {
51501 /* heaphdr:
51502 * - is not reachable
51503 * - is an object
51504 * - is not a finalized object waiting for rescue/keep decision
51505 * - has a finalizer
51506 */
51507
51508 DUK_DD(DUK_DDPRINT("unreachable heap object will be "
51509 "finalized -> mark as finalizable "
51510 "and treat as a reachability root: %p",
51511 (void *) hdr));
51512 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
51513 DUK_HEAPHDR_SET_FINALIZABLE(hdr);
51514 count_finalizable++;
51515 }
51516
51517 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51518 }
51519
51520 if (count_finalizable == 0) {
51521 return;
51522 }
51523
51524 DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
51525 (long) count_finalizable));
51526
51527 hdr = heap->heap_allocated;
51528 while (hdr != NULL) {
51529 if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
51530 duk__mark_heaphdr_nonnull(heap, hdr);
51531 }
51532
51533 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51534 }
51535
51536 /* Caller will finish the marking process if we hit a recursion limit. */
51537}
51538#endif /* DUK_USE_FINALIZER_SUPPORT */
51539
51540/*
51541 * Mark objects on finalize_list.
51542 */
51543
51544#if defined(DUK_USE_FINALIZER_SUPPORT)
51545DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
51546 duk_heaphdr *hdr;
51547#if defined(DUK_USE_DEBUG)
51548 duk_size_t count_finalize_list = 0;
51549#endif
51550
51551 DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
51552
51553 hdr = heap->finalize_list;
51554 while (hdr != NULL) {
51555 duk__mark_heaphdr_nonnull(heap, hdr);
51556 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51557#if defined(DUK_USE_DEBUG)
51558 count_finalize_list++;
51559#endif
51560 }
51561
51562#if defined(DUK_USE_DEBUG)
51563 if (count_finalize_list > 0) {
51564 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
51565 (long) count_finalize_list));
51566 }
51567#endif
51568}
51569#endif /* DUK_USE_FINALIZER_SUPPORT */
51570
51571/*
51572 * Fallback marking handler if recursion limit is reached.
51573 *
51574 * Iterates 'temproots' until recursion limit is no longer hit. Temproots
51575 * can be in heap_allocated or finalize_list; refzero_list is now always
51576 * empty for mark-and-sweep. A temproot may occur in finalize_list now if
51577 * there are objects on the finalize_list and user code creates a reference
51578 * from an object in heap_allocated to the object in finalize_list (which is
51579 * now allowed), and it happened to coincide with the recursion depth limit.
51580 *
51581 * This is a slow scan, but guarantees that we finish with a bounded C stack.
51582 *
51583 * Note that nodes may have been marked as temproots before this scan begun,
51584 * OR they may have been marked during the scan (as we process nodes
51585 * recursively also during the scan). This is intended behavior.
51586 */
51587
51588#if defined(DUK_USE_DEBUG)
51589DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
51590#else
51591DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
51592#endif
51593 DUK_ASSERT(hdr != NULL);
51594
51595 if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
51596 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
51597 return;
51598 }
51599
51600 DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
51601 DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
51602 DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */
51603#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
51604 hdr->h_assert_refcount--; /* Same node visited twice. */
51605#endif
51606 duk__mark_heaphdr_nonnull(heap, hdr);
51607
51608#if defined(DUK_USE_DEBUG)
51609 (*count)++;
51610#endif
51611}
51612
51613DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
51614 duk_heaphdr *hdr;
51615#if defined(DUK_USE_DEBUG)
51616 duk_size_t count;
51617#endif
51618
51619 DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
51620
51621 while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
51622 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
51623
51624#if defined(DUK_USE_DEBUG)
51625 count = 0;
51626#endif
51627 DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
51628
51629 hdr = heap->heap_allocated;
51630 while (hdr) {
51631#if defined(DUK_USE_DEBUG)
51632 duk__handle_temproot(heap, hdr, &count);
51633#else
51634 duk__handle_temproot(heap, hdr);
51635#endif
51636 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51637 }
51638
51639#if defined(DUK_USE_FINALIZER_SUPPORT)
51640 hdr = heap->finalize_list;
51641 while (hdr) {
51642#if defined(DUK_USE_DEBUG)
51643 duk__handle_temproot(heap, hdr, &count);
51644#else
51645 duk__handle_temproot(heap, hdr);
51646#endif
51647 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51648 }
51649#endif
51650
51651#if defined(DUK_USE_DEBUG)
51652 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
51653#endif
51654 }
51655}
51656
51657/*
51658 * Finalize refcounts for heap elements just about to be freed.
51659 * This must be done for all objects before freeing to avoid any
51660 * stale pointer dereferences.
51661 *
51662 * Note that this must deduce the set of objects to be freed
51663 * identically to duk__sweep_heap().
51664 */
51665
51666#if defined(DUK_USE_REFERENCE_COUNTING)
51667DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
51668 duk_heaphdr *hdr;
51669
51670 DUK_ASSERT(heap->heap_thread != NULL);
51671
51672 DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap));
51673
51674 hdr = heap->heap_allocated;
51675 while (hdr) {
51676 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
51677 /*
51678 * Unreachable object about to be swept. Finalize target refcounts
51679 * (objects which the unreachable object points to) without doing
51680 * refzero processing. Recursive decrefs are also prevented when
51681 * refzero processing is disabled.
51682 *
51683 * Value cannot be a finalizable object, as they have been made
51684 * temporarily reachable for this round.
51685 */
51686
51687 DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
51688
51689 /* Finalize using heap->heap_thread; DECREF has a
51690 * suppress check for mark-and-sweep which is based
51691 * on heap->ms_running.
51692 */
51693 duk_heaphdr_refcount_finalize_norz(heap, hdr);
51694 }
51695
51696 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51697 }
51698}
51699#endif /* DUK_USE_REFERENCE_COUNTING */
51700
51701/*
51702 * Clear (reachable) flags of finalize_list.
51703 *
51704 * We could mostly do in the sweep phase when we move objects from the
51705 * heap into the finalize_list. However, if a finalizer run is skipped
51706 * during a mark-and-sweep, the objects on the finalize_list will be marked
51707 * reachable during the next mark-and-sweep. Since they're already on the
51708 * finalize_list, no-one will be clearing their REACHABLE flag so we do it
51709 * here. (This now overlaps with the sweep handling in a harmless way.)
51710 */
51711
51712#if defined(DUK_USE_FINALIZER_SUPPORT)
51713DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
51714 duk_heaphdr *hdr;
51715
51716 DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
51717
51718 hdr = heap->finalize_list;
51719 while (hdr) {
51720 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
51721#if defined(DUK_USE_ASSERTIONS)
51722 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \
51723 (heap->currently_finalizing == hdr));
51724#endif
51725 /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */
51726 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
51727 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
51728 }
51729}
51730#endif /* DUK_USE_FINALIZER_SUPPORT */
51731
51732/*
51733 * Sweep stringtable.
51734 */
51735
51736DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) {
51737 duk_hstring *h;
51738 duk_hstring *prev;
51739 duk_uint32_t i;
51740#if defined(DUK_USE_DEBUG)
51741 duk_size_t count_free = 0;
51742#endif
51743 duk_size_t count_keep = 0;
51744
51745 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
51746
51747#if defined(DUK_USE_STRTAB_PTRCOMP)
51748 if (heap->strtable16 == NULL) {
51749#else
51750 if (heap->strtable == NULL) {
51751#endif
51752 goto done;
51753 }
51754
51755 for (i = 0; i < heap->st_size; i++) {
51756#if defined(DUK_USE_STRTAB_PTRCOMP)
51757 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
51758#else
51759 h = heap->strtable[i];
51760#endif
51761 prev = NULL;
51762 while (h != NULL) {
51763 duk_hstring *next;
51764 next = h->hdr.h_next;
51765
51766 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h))
51767 {
51768 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
51769 count_keep++;
51770 prev = h;
51771 } else {
51772#if defined(DUK_USE_DEBUG)
51773 count_free++;
51774#endif
51775
51776 /* For pinned strings the refcount has been
51777 * bumped. We could unbump it here before
51778 * freeing, but that's actually not necessary
51779 * except for assertions.
51780 */
51781#if 0
51782 if (DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
51783 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) > 0U);
51784 DUK_HSTRING_DECREF_NORZ(heap->heap_thread, h);
51785 DUK_HSTRING_CLEAR_PINNED_LITERAL(h);
51786 }
51787#endif
51788#if defined(DUK_USE_REFERENCE_COUNTING)
51789 /* Non-zero refcounts should not happen for unreachable strings,
51790 * because we refcount finalize all unreachable objects which
51791 * should have decreased unreachable string refcounts to zero
51792 * (even for cycles). However, pinned strings have a +1 bump.
51793 */
51794 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) ==
51795 DUK_HSTRING_HAS_PINNED_LITERAL(h) ? 1U : 0U);
51796#endif
51797
51798 /* Deal with weak references first. */
51799 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
51800
51801 /* Remove the string from the string table. */
51802 duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev);
51803
51804 /* Free inner references (these exist e.g. when external
51805 * strings are enabled) and the struct itself.
51806 */
51807 duk_free_hstring(heap, (duk_hstring *) h);
51808
51809 /* Don't update 'prev'; it should be last string kept. */
51810 }
51811
51812 h = next;
51813 }
51814 }
51815
51816 done:
51817#if defined(DUK_USE_DEBUG)
51818 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
51819 (long) count_free, (long) count_keep));
51820#endif
51821 *out_count_keep = count_keep;
51822}
51823
51824/*
51825 * Sweep heap.
51826 */
51827
51828DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) {
51829 duk_heaphdr *prev; /* last element that was left in the heap */
51830 duk_heaphdr *curr;
51831 duk_heaphdr *next;
51832#if defined(DUK_USE_DEBUG)
51833 duk_size_t count_free = 0;
51834 duk_size_t count_finalize = 0;
51835 duk_size_t count_rescue = 0;
51836#endif
51837 duk_size_t count_keep = 0;
51838
51839 DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
51840
51841 prev = NULL;
51842 curr = heap->heap_allocated;
51843 heap->heap_allocated = NULL;
51844 while (curr) {
51845 /* Strings and ROM objects are never placed on the heap allocated list. */
51846 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
51847 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
51848
51849 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
51850
51851 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
51852 /*
51853 * Reachable object:
51854 * - If FINALIZABLE -> actually unreachable (but marked
51855 * artificially reachable), queue to finalize_list.
51856 * - If !FINALIZABLE but FINALIZED -> rescued after
51857 * finalizer execution.
51858 * - Otherwise just a normal, reachable object.
51859 *
51860 * Objects which are kept are queued to heap_allocated
51861 * tail (we're essentially filtering heap_allocated in
51862 * practice).
51863 */
51864
51865#if defined(DUK_USE_FINALIZER_SUPPORT)
51866 if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) {
51867 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
51868 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
51869 DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr));
51870
51871#if defined(DUK_USE_REFERENCE_COUNTING)
51872 DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */
51873#endif
51874 DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr);
51875#if defined(DUK_USE_DEBUG)
51876 count_finalize++;
51877#endif
51878 }
51879 else
51880#endif /* DUK_USE_FINALIZER_SUPPORT */
51881 {
51882 if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) {
51883 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
51884 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
51885
51886 if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) {
51887 DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr));
51888 count_keep++;
51889 } else {
51890 DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr));
51891#if defined(DUK_USE_FINALIZER_SUPPORT)
51892 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
51893#endif
51894#if defined(DUK_USE_DEBUG)
51895 count_rescue++;
51896#endif
51897 }
51898 } else {
51899 DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr));
51900 count_keep++;
51901 }
51902
51903 if (prev != NULL) {
51904 DUK_ASSERT(heap->heap_allocated != NULL);
51905 DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
51906 } else {
51907 DUK_ASSERT(heap->heap_allocated == NULL);
51908 heap->heap_allocated = curr;
51909 }
51910#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
51911 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
51912#endif
51913 DUK_HEAPHDR_ASSERT_LINKS(heap, prev);
51914 DUK_HEAPHDR_ASSERT_LINKS(heap, curr);
51915 prev = curr;
51916 }
51917
51918 /*
51919 * Shrink check for value stacks here. We're inside
51920 * ms_prevent_count protection which prevents recursive
51921 * mark-and-sweep and refzero finalizers, so there are
51922 * no side effects that would affect the heap lists.
51923 */
51924 if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) {
51925 duk_hthread *thr_curr = (duk_hthread *) curr;
51926 DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O", curr));
51927 duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/);
51928 }
51929
51930 DUK_HEAPHDR_CLEAR_REACHABLE(curr);
51931 /* Keep FINALIZED if set, used if rescue decisions are postponed. */
51932 /* Keep FINALIZABLE for objects on finalize_list. */
51933 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
51934 } else {
51935 /*
51936 * Unreachable object:
51937 * - If FINALIZED, object was finalized but not
51938 * rescued. This doesn't affect freeing.
51939 * - Otherwise normal unreachable object.
51940 *
51941 * There's no guard preventing a FINALIZED object
51942 * from being freed while finalizers execute: the
51943 * artificial finalize_list reachability roots can't
51944 * cause an incorrect free decision (but can cause
51945 * an incorrect rescue decision).
51946 */
51947
51948#if defined(DUK_USE_REFERENCE_COUNTING)
51949 /* Non-zero refcounts should not happen because we refcount
51950 * finalize all unreachable objects which should cancel out
51951 * refcounts (even for cycles).
51952 */
51953 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
51954#endif
51955 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
51956
51957#if defined(DUK_USE_DEBUG)
51958 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
51959 DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr));
51960 } else {
51961 DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr));
51962 }
51963
51964#endif
51965
51966 /* Note: object cannot be a finalizable unreachable object, as
51967 * they have been marked temporarily reachable for this round,
51968 * and are handled above.
51969 */
51970
51971#if defined(DUK_USE_DEBUG)
51972 count_free++;
51973#endif
51974
51975 /* Weak refs should be handled here, but no weak refs for
51976 * any non-string objects exist right now.
51977 */
51978
51979 /* Free object and all auxiliary (non-heap) allocs. */
51980 duk_heap_free_heaphdr_raw(heap, curr);
51981 }
51982
51983 curr = next;
51984 }
51985
51986 if (prev != NULL) {
51987 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
51988 }
51989 DUK_HEAPHDR_ASSERT_LINKS(heap, prev);
51990
51991#if defined(DUK_USE_DEBUG)
51992 DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
51993 (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
51994#endif
51995 *out_count_keep = count_keep;
51996}
51997
51998/*
51999 * Litcache helpers.
52000 */
52001
52002#if defined(DUK_USE_LITCACHE_SIZE)
52003DUK_LOCAL void duk__wipe_litcache(duk_heap *heap) {
52004 duk_uint_t i;
52005 duk_litcache_entry *e;
52006
52007 e = heap->litcache;
52008 for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
52009 e->addr = NULL;
52010 /* e->h does not need to be invalidated: when e->addr is
52011 * NULL, e->h is considered garbage.
52012 */
52013 e++;
52014 }
52015}
52016#endif /* DUK_USE_LITCACHE_SIZE */
52017
52018/*
52019 * Object compaction.
52020 *
52021 * Compaction is assumed to never throw an error.
52022 */
52023
52024DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) {
52025 duk_hobject *obj;
52026 /* XXX: for threads, compact stacks? */
52027
52028 DUK_UNREF(udata);
52029 obj = duk_known_hobject(thr, -1);
52030 duk_hobject_compact_props(thr, obj);
52031 return 0;
52032}
52033
52034#if defined(DUK_USE_DEBUG)
52035DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) {
52036#else
52037DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
52038#endif
52039 duk_heaphdr *curr;
52040#if defined(DUK_USE_DEBUG)
52041 duk_size_t old_size, new_size;
52042#endif
52043 duk_hobject *obj;
52044
52045 DUK_UNREF(heap);
52046
52047 curr = start;
52048 while (curr) {
52049 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
52050
52051 if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
52052 goto next;
52053 }
52054 obj = (duk_hobject *) curr;
52055
52056#if defined(DUK_USE_DEBUG)
52057 old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
52058 DUK_HOBJECT_GET_ASIZE(obj),
52059 DUK_HOBJECT_GET_HSIZE(obj));
52060#endif
52061
52062 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
52063 duk_push_hobject(thr, obj);
52064 /* XXX: disable error handlers for duration of compaction? */
52065 duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0);
52066
52067#if defined(DUK_USE_DEBUG)
52068 new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
52069 DUK_HOBJECT_GET_ASIZE(obj),
52070 DUK_HOBJECT_GET_HSIZE(obj));
52071#endif
52072
52073#if defined(DUK_USE_DEBUG)
52074 (*p_count_compact)++;
52075 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
52076#endif
52077
52078 next:
52079 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
52080#if defined(DUK_USE_DEBUG)
52081 (*p_count_check)++;
52082#endif
52083 }
52084}
52085
52086DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
52087 /* XXX: which lists should participate? to be finalized? */
52088#if defined(DUK_USE_DEBUG)
52089 duk_size_t count_check = 0;
52090 duk_size_t count_compact = 0;
52091 duk_size_t count_bytes_saved = 0;
52092#endif
52093
52094 DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
52095
52096 DUK_ASSERT(heap->heap_thread != NULL);
52097
52098#if defined(DUK_USE_DEBUG)
52099 duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
52100#if defined(DUK_USE_FINALIZER_SUPPORT)
52101 duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
52102#endif
52103#else
52104 duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated);
52105#if defined(DUK_USE_FINALIZER_SUPPORT)
52106 duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list);
52107#endif
52108#endif
52109#if defined(DUK_USE_REFERENCE_COUNTING)
52110 DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
52111#endif
52112
52113#if defined(DUK_USE_DEBUG)
52114 DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
52115 (long) count_check, (long) count_compact, (long) count_bytes_saved));
52116#endif
52117}
52118
52119/*
52120 * Assertion helpers.
52121 */
52122
52123#if defined(DUK_USE_ASSERTIONS)
52124typedef void (*duk__gc_heaphdr_assert)(duk_heap *heap, duk_heaphdr *h);
52125typedef void (*duk__gc_hstring_assert)(duk_heap *heap, duk_hstring *h);
52126
52127DUK_LOCAL void duk__assert_walk_list(duk_heap *heap, duk_heaphdr *start, duk__gc_heaphdr_assert func) {
52128 duk_heaphdr *curr;
52129 for (curr = start; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
52130 func(heap, curr);
52131 }
52132}
52133
52134DUK_LOCAL void duk__assert_walk_strtable(duk_heap *heap, duk__gc_hstring_assert func) {
52135 duk_uint32_t i;
52136
52137 for (i = 0; i < heap->st_size; i++) {
52138 duk_hstring *h;
52139
52140#if defined(DUK_USE_STRTAB_PTRCOMP)
52141 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
52142#else
52143 h = heap->strtable[i];
52144#endif
52145 while (h != NULL) {
52146 func(heap, h);
52147 h = h->hdr.h_next;
52148 }
52149 }
52150}
52151
52152DUK_LOCAL void duk__assert_heaphdr_flags_cb(duk_heap *heap, duk_heaphdr *h) {
52153 DUK_UNREF(heap);
52154 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(h));
52155 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(h));
52156 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h));
52157 /* may have FINALIZED */
52158}
52159DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
52160 duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_heaphdr_flags_cb);
52161#if defined(DUK_USE_REFERENCE_COUNTING)
52162 DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
52163#endif
52164 /* XXX: Assertions for finalize_list? */
52165}
52166
52167DUK_LOCAL void duk__assert_validity_cb1(duk_heap *heap, duk_heaphdr *h) {
52168 DUK_UNREF(heap);
52169 DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT(h) || DUK_HEAPHDR_IS_BUFFER(h));
52170 duk_heaphdr_assert_valid_subclassed(h);
52171}
52172DUK_LOCAL void duk__assert_validity_cb2(duk_heap *heap, duk_hstring *h) {
52173 DUK_UNREF(heap);
52174 DUK_ASSERT(DUK_HEAPHDR_IS_STRING((duk_heaphdr *) h));
52175 duk_heaphdr_assert_valid_subclassed((duk_heaphdr *) h);
52176}
52177DUK_LOCAL void duk__assert_validity(duk_heap *heap) {
52178 duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_validity_cb1);
52179#if defined(DUK_USE_FINALIZER_SUPPORT)
52180 duk__assert_walk_list(heap, heap->finalize_list, duk__assert_validity_cb1);
52181#endif
52182#if defined(DUK_USE_REFERENCE_COUNTING)
52183 duk__assert_walk_list(heap, heap->refzero_list, duk__assert_validity_cb1);
52184#endif
52185 duk__assert_walk_strtable(heap, duk__assert_validity_cb2);
52186}
52187
52188#if defined(DUK_USE_REFERENCE_COUNTING)
52189DUK_LOCAL void duk__assert_valid_refcounts_cb(duk_heap *heap, duk_heaphdr *h) {
52190 /* Cannot really assert much w.r.t. refcounts now. */
52191
52192 DUK_UNREF(heap);
52193 if (DUK_HEAPHDR_GET_REFCOUNT(h) == 0 &&
52194 DUK_HEAPHDR_HAS_FINALIZED(h)) {
52195 /* An object may be in heap_allocated list with a zero
52196 * refcount if it has just been finalized and is waiting
52197 * to be collected by the next cycle.
52198 * (This doesn't currently happen however.)
52199 */
52200 } else if (DUK_HEAPHDR_GET_REFCOUNT(h) == 0) {
52201 /* An object may be in heap_allocated list with a zero
52202 * refcount also if it is a temporary object created
52203 * during debugger paused state. It will get collected
52204 * by mark-and-sweep based on its reachability status
52205 * (presumably not reachable because refcount is 0).
52206 */
52207 }
52208 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); /* Unsigned. */
52209}
52210DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
52211 duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_valid_refcounts_cb);
52212}
52213
52214DUK_LOCAL void duk__clear_assert_refcounts_cb1(duk_heap *heap, duk_heaphdr *h) {
52215 DUK_UNREF(heap);
52216 h->h_assert_refcount = 0;
52217}
52218DUK_LOCAL void duk__clear_assert_refcounts_cb2(duk_heap *heap, duk_hstring *h) {
52219 DUK_UNREF(heap);
52220 ((duk_heaphdr *) h)->h_assert_refcount = 0;
52221}
52222DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) {
52223 duk__assert_walk_list(heap, heap->heap_allocated, duk__clear_assert_refcounts_cb1);
52224#if defined(DUK_USE_FINALIZER_SUPPORT)
52225 duk__assert_walk_list(heap, heap->finalize_list, duk__clear_assert_refcounts_cb1);
52226#endif
52227#if defined(DUK_USE_REFERENCE_COUNTING)
52228 duk__assert_walk_list(heap, heap->refzero_list, duk__clear_assert_refcounts_cb1);
52229#endif
52230 duk__assert_walk_strtable(heap, duk__clear_assert_refcounts_cb2);
52231}
52232
52233DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) {
52234 duk_bool_t count_ok;
52235 duk_size_t expect_refc;
52236
52237 /* The refcount check only makes sense for reachable objects on
52238 * heap_allocated or string table, after the sweep phase. Prior to
52239 * sweep phase refcounts will include references that are not visible
52240 * via reachability roots.
52241 *
52242 * Because we're called after the sweep phase, all heap objects on
52243 * heap_allocated are reachable. REACHABLE flags have already been
52244 * cleared so we can't check them.
52245 */
52246
52247 /* ROM objects have intentionally incorrect refcount (1), but we won't
52248 * check them.
52249 */
52250 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
52251
52252 expect_refc = hdr->h_assert_refcount;
52253 if (DUK_HEAPHDR_IS_STRING(hdr) && DUK_HSTRING_HAS_PINNED_LITERAL((duk_hstring *) hdr)) {
52254 expect_refc++;
52255 }
52256 count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == expect_refc);
52257 if (!count_ok) {
52258 DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO",
52259 (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr),
52260 (long) hdr->h_assert_refcount, hdr));
52261 DUK_ASSERT(0);
52262 }
52263}
52264
52265DUK_LOCAL void duk__check_assert_refcounts_cb1(duk_heap *heap, duk_heaphdr *h) {
52266 DUK_UNREF(heap);
52267 duk__check_refcount_heaphdr(h);
52268}
52269DUK_LOCAL void duk__check_assert_refcounts_cb2(duk_heap *heap, duk_hstring *h) {
52270 DUK_UNREF(heap);
52271 duk__check_refcount_heaphdr((duk_heaphdr *) h);
52272}
52273DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) {
52274 duk__assert_walk_list(heap, heap->heap_allocated, duk__check_assert_refcounts_cb1);
52275#if defined(DUK_USE_FINALIZER_SUPPORT)
52276 duk__assert_walk_list(heap, heap->finalize_list, duk__check_assert_refcounts_cb1);
52277#endif
52278 /* XXX: Assert anything for refzero_list? */
52279 duk__assert_walk_strtable(heap, duk__check_assert_refcounts_cb2);
52280}
52281#endif /* DUK_USE_REFERENCE_COUNTING */
52282
52283#if defined(DUK_USE_LITCACHE_SIZE)
52284DUK_LOCAL void duk__assert_litcache_nulls(duk_heap *heap) {
52285 duk_uint_t i;
52286 duk_litcache_entry *e;
52287
52288 e = heap->litcache;
52289 for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
52290 /* Entry addresses were NULLed before mark-and-sweep, check
52291 * that they're still NULL afterwards to ensure no pointers
52292 * were recorded through any side effects.
52293 */
52294 DUK_ASSERT(e->addr == NULL);
52295 }
52296}
52297#endif /* DUK_USE_LITCACHE_SIZE */
52298#endif /* DUK_USE_ASSERTIONS */
52299
52300/*
52301 * Stats dump.
52302 */
52303
52304#if defined(DUK_USE_DEBUG)
52305DUK_LOCAL void duk__dump_stats(duk_heap *heap) {
52306 DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld",
52307 (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt,
52308 (long) heap->stats_exec_throw));
52309 DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld",
52310 (long) heap->stats_call_all, (long) heap->stats_call_tailcall,
52311 (long) heap->stats_call_ecmatoecma));
52312 DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld",
52313 (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow,
52314 (long) heap->stats_safecall_throw));
52315 DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld",
52316 (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count,
52317 (long) heap->stats_ms_emergency_count));
52318 DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, "
52319 "resize_check=%ld, resize_grow=%ld, resize_shrink=%ld, "
52320 "litcache_hit=%ld, litcache_miss=%ld, litcache_pin=%ld",
52321 (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss,
52322 (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow,
52323 (long) heap->stats_strtab_resize_shrink, (long) heap->stats_strtab_litcache_hit,
52324 (long) heap->stats_strtab_litcache_miss, (long) heap->stats_strtab_litcache_pin));
52325 DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld",
52326 (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array));
52327 DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld",
52328 (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit,
52329 (long) heap->stats_getownpropdesc_miss));
52330 DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld",
52331 (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit,
52332 (long) heap->stats_getpropdesc_miss));
52333 DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
52334 "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, "
52335 "proxy=%ld, arguments=%ld",
52336 (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx,
52337 (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx,
52338 (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx,
52339 (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy,
52340 (long) heap->stats_getprop_arguments));
52341 DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
52342 "bufferidx=%ld, proxy=%ld",
52343 (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx,
52344 (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx,
52345 (long) heap->stats_putprop_proxy));
52346 DUK_D(DUK_DPRINT("stats getvar: all=%ld",
52347 (long) heap->stats_getvar_all));
52348 DUK_D(DUK_DPRINT("stats putvar: all=%ld",
52349 (long) heap->stats_putvar_all));
52350 DUK_D(DUK_DPRINT("stats envrec: delayedcreate=%ld, create=%ld, newenv=%ld, oldenv=%ld, pushclosure=%ld",
52351 (long) heap->stats_envrec_delayedcreate,
52352 (long) heap->stats_envrec_create,
52353 (long) heap->stats_envrec_newenv,
52354 (long) heap->stats_envrec_oldenv,
52355 (long) heap->stats_envrec_pushclosure));
52356}
52357#endif /* DUK_USE_DEBUG */
52358
52359/*
52360 * Main mark-and-sweep function.
52361 *
52362 * 'flags' represents the features requested by the caller. The current
52363 * heap->ms_base_flags is ORed automatically into the flags; the base flags
52364 * mask typically prevents certain mark-and-sweep operation to avoid trouble.
52365 */
52366
52367DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
52368 duk_size_t count_keep_obj;
52369 duk_size_t count_keep_str;
52370#if defined(DUK_USE_VOLUNTARY_GC)
52371 duk_size_t tmp;
52372#endif
52373 duk_bool_t entry_creating_error;
52374
52375 DUK_STATS_INC(heap, stats_ms_try_count);
52376#if defined(DUK_USE_DEBUG)
52377 if (flags & DUK_MS_FLAG_EMERGENCY) {
52378 DUK_STATS_INC(heap, stats_ms_emergency_count);
52379 }
52380#endif
52381
52382 /* If debugger is paused, garbage collection is disabled by default.
52383 * This is achieved by bumping ms_prevent_count when becoming paused.
52384 */
52385 DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0);
52386
52387 /* Prevention/recursion check as soon as possible because we may
52388 * be called a number of times when voluntary mark-and-sweep is
52389 * pending.
52390 */
52391 if (heap->ms_prevent_count != 0) {
52392 DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep"));
52393 DUK_STATS_INC(heap, stats_ms_skip_count);
52394 return;
52395 }
52396 DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */
52397
52398 /* Heap_thread is used during mark-and-sweep for refcount finalization
52399 * (it's also used for finalizer execution once mark-and-sweep is
52400 * complete). Heap allocation code ensures heap_thread is set and
52401 * properly initialized before setting ms_prevent_count to 0.
52402 */
52403 DUK_ASSERT(heap->heap_thread != NULL);
52404 DUK_ASSERT(heap->heap_thread->valstack != NULL);
52405
52406 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
52407 (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags)));
52408
52409 flags |= heap->ms_base_flags;
52410#if defined(DUK_USE_FINALIZER_SUPPORT)
52411 if (heap->finalize_list != NULL) {
52412 flags |= DUK_MS_FLAG_POSTPONE_RESCUE;
52413 }
52414#endif
52415
52416 /*
52417 * Assertions before
52418 */
52419
52420#if defined(DUK_USE_ASSERTIONS)
52421 DUK_ASSERT(heap->ms_prevent_count == 0);
52422 DUK_ASSERT(heap->ms_running == 0);
52423 DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap));
52424 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
52425 DUK_ASSERT(heap->ms_recursion_depth == 0);
52426 duk__assert_heaphdr_flags(heap);
52427 duk__assert_validity(heap);
52428#if defined(DUK_USE_REFERENCE_COUNTING)
52429 /* Note: heap->refzero_free_running may be true; a refcount
52430 * finalizer may trigger a mark-and-sweep.
52431 */
52432 duk__assert_valid_refcounts(heap);
52433#endif /* DUK_USE_REFERENCE_COUNTING */
52434#endif /* DUK_USE_ASSERTIONS */
52435
52436 /*
52437 * Begin
52438 */
52439
52440 DUK_ASSERT(heap->ms_prevent_count == 0);
52441 DUK_ASSERT(heap->ms_running == 0);
52442 heap->ms_prevent_count = 1;
52443 heap->ms_running = 1;
52444 entry_creating_error = heap->creating_error;
52445 heap->creating_error = 0;
52446
52447 /*
52448 * Free activation/catcher freelists on every mark-and-sweep for now.
52449 * This is an initial rough draft; ideally we'd keep count of the
52450 * freelist size and free only excess entries.
52451 */
52452
52453 DUK_D(DUK_DPRINT("freeing temporary freelists"));
52454 duk_heap_free_freelists(heap);
52455
52456 /*
52457 * Mark roots, hoping that recursion limit is not normally hit.
52458 * If recursion limit is hit, run additional reachability rounds
52459 * starting from "temproots" until marking is complete.
52460 *
52461 * Marking happens in two phases: first we mark actual reachability
52462 * roots (and run "temproots" to complete the process). Then we
52463 * check which objects are unreachable and are finalizable; such
52464 * objects are marked as FINALIZABLE and marked as reachability
52465 * (and "temproots" is run again to complete the process).
52466 *
52467 * The heap finalize_list must also be marked as a reachability root.
52468 * There may be objects on the list from a previous round if the
52469 * previous run had finalizer skip flag.
52470 */
52471
52472#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
52473 duk__clear_assert_refcounts(heap);
52474#endif
52475#if defined(DUK_USE_LITCACHE_SIZE)
52476 duk__wipe_litcache(heap);
52477#endif
52478 duk__mark_roots_heap(heap); /* Mark main reachability roots. */
52479#if defined(DUK_USE_REFERENCE_COUNTING)
52480 DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
52481#endif
52482 duk__mark_temproots_by_heap_scan(heap); /* Temproots. */
52483
52484#if defined(DUK_USE_FINALIZER_SUPPORT)
52485 duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */
52486 duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */
52487#endif
52488 duk__mark_temproots_by_heap_scan(heap); /* Temproots. */
52489
52490 /*
52491 * Sweep garbage and remove marking flags, and move objects with
52492 * finalizers to the finalizer work list.
52493 *
52494 * Objects to be swept need to get their refcounts finalized before
52495 * they are swept. In other words, their target object refcounts
52496 * need to be decreased. This has to be done before freeing any
52497 * objects to avoid decref'ing dangling pointers (which may happen
52498 * even without bugs, e.g. with reference loops)
52499 *
52500 * Because strings don't point to other heap objects, similar
52501 * finalization is not necessary for strings.
52502 */
52503
52504 /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
52505
52506#if defined(DUK_USE_REFERENCE_COUNTING)
52507 duk__finalize_refcounts(heap);
52508#endif
52509 duk__sweep_heap(heap, flags, &count_keep_obj);
52510 duk__sweep_stringtable(heap, &count_keep_str);
52511#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
52512 duk__check_assert_refcounts(heap);
52513#endif
52514#if defined(DUK_USE_REFERENCE_COUNTING)
52515 DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
52516#endif
52517#if defined(DUK_USE_FINALIZER_SUPPORT)
52518 duk__clear_finalize_list_flags(heap);
52519#endif
52520
52521 /*
52522 * Object compaction (emergency only).
52523 *
52524 * Object compaction is a separate step after sweeping, as there is
52525 * more free memory for it to work with. Also, currently compaction
52526 * may insert new objects into the heap allocated list and the string
52527 * table which we don't want to do during a sweep (the reachability
52528 * flags of such objects would be incorrect). The objects inserted
52529 * are currently:
52530 *
52531 * - a temporary duk_hbuffer for a new properties allocation
52532 * - if array part is abandoned, string keys are interned
52533 *
52534 * The object insertions go to the front of the list, so they do not
52535 * cause an infinite loop (they are not compacted).
52536 *
52537 * At present compaction is not allowed when mark-and-sweep runs
52538 * during error handling because it involves a duk_safe_call()
52539 * interfering with error state.
52540 */
52541
52542 if ((flags & DUK_MS_FLAG_EMERGENCY) &&
52543 !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
52544 if (heap->lj.type != DUK_LJ_TYPE_UNKNOWN) {
52545 DUK_D(DUK_DPRINT("lj.type (%ld) not DUK_LJ_TYPE_UNKNOWN, skip object compaction", (long) heap->lj.type));
52546 } else {
52547 DUK_D(DUK_DPRINT("object compaction"));
52548 duk__compact_objects(heap);
52549 }
52550 }
52551
52552 /*
52553 * String table resize check.
52554 *
52555 * This is mainly useful in emergency GC: if the string table load
52556 * factor is really low for some reason, we can shrink the string
52557 * table to a smaller size and free some memory in the process.
52558 * Only execute in emergency GC. String table has internal flags
52559 * to protect against recursive resizing if this mark-and-sweep pass
52560 * was triggered by a string table resize.
52561 */
52562
52563 if (flags & DUK_MS_FLAG_EMERGENCY) {
52564 DUK_D(DUK_DPRINT("stringtable resize check in emergency gc"));
52565 duk_heap_strtable_force_resize(heap);
52566 }
52567
52568 /*
52569 * Finish
52570 */
52571
52572 DUK_ASSERT(heap->ms_prevent_count == 1);
52573 DUK_ASSERT(heap->ms_running == 1);
52574 heap->ms_prevent_count = 0;
52575 heap->ms_running = 0;
52576 heap->creating_error = entry_creating_error; /* for nested error handling, see GH-2278 */
52577
52578 /*
52579 * Assertions after
52580 */
52581
52582#if defined(DUK_USE_ASSERTIONS)
52583 DUK_ASSERT(heap->ms_prevent_count == 0);
52584 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
52585 DUK_ASSERT(heap->ms_recursion_depth == 0);
52586 duk__assert_heaphdr_flags(heap);
52587 duk__assert_validity(heap);
52588#if defined(DUK_USE_REFERENCE_COUNTING)
52589 /* Note: heap->refzero_free_running may be true; a refcount
52590 * finalizer may trigger a mark-and-sweep.
52591 */
52592 duk__assert_valid_refcounts(heap);
52593#endif /* DUK_USE_REFERENCE_COUNTING */
52594#if defined(DUK_USE_LITCACHE_SIZE)
52595 duk__assert_litcache_nulls(heap);
52596#endif /* DUK_USE_LITCACHE_SIZE */
52597#endif /* DUK_USE_ASSERTIONS */
52598
52599 /*
52600 * Reset trigger counter
52601 */
52602
52603#if defined(DUK_USE_VOLUNTARY_GC)
52604 tmp = (count_keep_obj + count_keep_str) / 256;
52605 heap->ms_trigger_counter = (duk_int_t) (
52606 (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
52607 DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
52608 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
52609 (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter));
52610#else
52611 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
52612 (long) count_keep_obj, (long) count_keep_str));
52613#endif
52614
52615 /*
52616 * Stats dump
52617 */
52618
52619#if defined(DUK_USE_DEBUG)
52620 duk__dump_stats(heap);
52621#endif
52622
52623 /*
52624 * Finalize objects in the finalization work list. Finalized
52625 * objects are queued back to heap_allocated with FINALIZED set.
52626 *
52627 * Since finalizers may cause arbitrary side effects, they are
52628 * prevented e.g. during string table and object property allocation
52629 * resizing using heap->pf_prevent_count. In this case the objects
52630 * remain in the finalization work list after mark-and-sweep exits
52631 * and they may be finalized on the next pass or any DECREF checking
52632 * for finalize_list.
52633 *
52634 * As of Duktape 2.1 finalization happens outside mark-and-sweep
52635 * protection. Mark-and-sweep is allowed while the finalize_list
52636 * is being processed, but no rescue decisions are done while the
52637 * process is on-going. This avoids incorrect rescue decisions
52638 * if an object is considered reachable (and thus rescued) because
52639 * of a reference via finalize_list (which is considered a reachability
52640 * root). When finalize_list is being processed, reachable objects
52641 * with FINALIZED set will just keep their FINALIZED flag for later
52642 * mark-and-sweep processing.
52643 *
52644 * This could also be handled (a bit better) by having a more refined
52645 * notion of reachability for rescue/free decisions.
52646 *
52647 * XXX: avoid finalizer execution when doing emergency GC?
52648 */
52649
52650#if defined(DUK_USE_FINALIZER_SUPPORT)
52651 /* Attempt to process finalize_list, pf_prevent_count check
52652 * is inside the target.
52653 */
52654 duk_heap_process_finalize_list(heap);
52655#endif /* DUK_USE_FINALIZER_SUPPORT */
52656}
52657#line 1 "duk_heap_memory.c"
52658/*
52659 * Memory allocation handling.
52660 */
52661
52662/* #include duk_internal.h -> already included */
52663
52664/*
52665 * Allocate memory with garbage collection.
52666 */
52667
52668/* Slow path: voluntary GC triggered, first alloc attempt failed, or zero size. */
52669DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_alloc_slowpath(duk_heap *heap, duk_size_t size) {
52670 void *res;
52671 duk_small_int_t i;
52672
52673 DUK_ASSERT(heap != NULL);
52674 DUK_ASSERT(heap->alloc_func != NULL);
52675 DUK_ASSERT_DISABLE(size >= 0);
52676
52677 if (size == 0) {
52678 DUK_D(DUK_DPRINT("zero size alloc in slow path, return NULL"));
52679 return NULL;
52680 }
52681
52682 DUK_D(DUK_DPRINT("first alloc attempt failed or voluntary GC limit reached, attempt to gc and retry"));
52683
52684#if 0
52685 /*
52686 * If GC is already running there is no point in attempting a GC
52687 * because it will be skipped. This could be checked for explicitly,
52688 * but it isn't actually needed: the loop below will eventually
52689 * fail resulting in a NULL.
52690 */
52691
52692 if (heap->ms_prevent_count != 0) {
52693 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
52694 return NULL;
52695 }
52696#endif
52697
52698 /*
52699 * Retry with several GC attempts. Initial attempts are made without
52700 * emergency mode; later attempts use emergency mode which minimizes
52701 * memory allocations forcibly.
52702 */
52703
52704 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
52705 duk_small_uint_t flags;
52706
52707 flags = 0;
52708 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
52709 flags |= DUK_MS_FLAG_EMERGENCY;
52710 }
52711
52712 duk_heap_mark_and_sweep(heap, flags);
52713
52714 DUK_ASSERT(size > 0);
52715 res = heap->alloc_func(heap->heap_udata, size);
52716 if (res != NULL) {
52717 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
52718 (long) (i + 1), (long) size));
52719 return res;
52720 }
52721 }
52722
52723 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
52724 return NULL;
52725}
52726
52727DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
52728 void *res;
52729
52730 DUK_ASSERT(heap != NULL);
52731 DUK_ASSERT(heap->alloc_func != NULL);
52732 DUK_ASSERT_DISABLE(size >= 0);
52733
52734#if defined(DUK_USE_VOLUNTARY_GC)
52735 /* Voluntary periodic GC (if enabled). */
52736 if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
52737 goto slowpath;
52738 }
52739#endif
52740
52741#if defined(DUK_USE_GC_TORTURE)
52742 /* Simulate alloc failure on every alloc, except when mark-and-sweep
52743 * is running.
52744 */
52745 if (heap->ms_prevent_count == 0) {
52746 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
52747 res = NULL;
52748 DUK_UNREF(res);
52749 goto slowpath;
52750 }
52751#endif
52752
52753 /* Zero-size allocation should happen very rarely (if at all), so
52754 * don't check zero size on NULL; handle it in the slow path
52755 * instead. This reduces size of inlined code.
52756 */
52757 res = heap->alloc_func(heap->heap_udata, size);
52758 if (DUK_LIKELY(res != NULL)) {
52759 return res;
52760 }
52761
52762 slowpath:
52763
52764 if (size == 0) {
52765 DUK_D(DUK_DPRINT("first alloc attempt returned NULL for zero size alloc, use slow path to deal with it"));
52766 } else {
52767 DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
52768 }
52769 return duk__heap_mem_alloc_slowpath(heap, size);
52770}
52771
52772DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
52773 void *res;
52774
52775 DUK_ASSERT(heap != NULL);
52776 DUK_ASSERT(heap->alloc_func != NULL);
52777 DUK_ASSERT_DISABLE(size >= 0);
52778
52779 res = DUK_ALLOC(heap, size);
52780 if (DUK_LIKELY(res != NULL)) {
52781 duk_memzero(res, size);
52782 }
52783 return res;
52784}
52785
52786DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) {
52787 void *res;
52788
52789 DUK_ASSERT(thr != NULL);
52790 DUK_ASSERT(thr->heap != NULL);
52791 DUK_ASSERT(thr->heap->alloc_func != NULL);
52792
52793 res = duk_heap_mem_alloc(thr->heap, size);
52794 if (DUK_LIKELY(res != NULL)) {
52795 return res;
52796 } else if (size == 0) {
52797 DUK_ASSERT(res == NULL);
52798 return res;
52799 }
52800 DUK_ERROR_ALLOC_FAILED(thr);
52801 DUK_WO_NORETURN(return NULL;);
52802}
52803
52804DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) {
52805 void *res;
52806
52807 DUK_ASSERT(thr != NULL);
52808 DUK_ASSERT(thr->heap != NULL);
52809 DUK_ASSERT(thr->heap->alloc_func != NULL);
52810
52811 res = duk_heap_mem_alloc(thr->heap, size);
52812 if (DUK_LIKELY(res != NULL)) {
52813 duk_memzero(res, size);
52814 return res;
52815 } else if (size == 0) {
52816 DUK_ASSERT(res == NULL);
52817 return res;
52818 }
52819 DUK_ERROR_ALLOC_FAILED(thr);
52820 DUK_WO_NORETURN(return NULL;);
52821}
52822
52823/*
52824 * Reallocate memory with garbage collection.
52825 */
52826
52827/* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */
52828DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_realloc_slowpath(duk_heap *heap, void *ptr, duk_size_t newsize) {
52829 void *res;
52830 duk_small_int_t i;
52831
52832 DUK_ASSERT(heap != NULL);
52833 DUK_ASSERT(heap->realloc_func != NULL);
52834 /* ptr may be NULL */
52835 DUK_ASSERT_DISABLE(newsize >= 0);
52836
52837 /* Newsize was 0 and realloc() returned NULL, this has the semantics
52838 * of free(oldptr), i.e. memory was successfully freed.
52839 */
52840 if (newsize == 0) {
52841 DUK_D(DUK_DPRINT("zero size realloc in slow path, return NULL"));
52842 return NULL;
52843 }
52844
52845 DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
52846
52847#if 0
52848 /*
52849 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
52850 */
52851
52852 if (heap->ms_prevent_count != 0) {
52853 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
52854 return NULL;
52855 }
52856#endif
52857
52858 /*
52859 * Retry with several GC attempts. Initial attempts are made without
52860 * emergency mode; later attempts use emergency mode which minimizes
52861 * memory allocations forcibly.
52862 */
52863
52864 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
52865 duk_small_uint_t flags;
52866
52867 flags = 0;
52868 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
52869 flags |= DUK_MS_FLAG_EMERGENCY;
52870 }
52871
52872 duk_heap_mark_and_sweep(heap, flags);
52873
52874 DUK_ASSERT(newsize > 0);
52875 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
52876 if (res || newsize == 0) {
52877 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
52878 (long) (i + 1), (long) newsize));
52879 return res;
52880 }
52881 }
52882
52883 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
52884 return NULL;
52885}
52886
52887DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
52888 void *res;
52889
52890 DUK_ASSERT(heap != NULL);
52891 DUK_ASSERT(heap->realloc_func != NULL);
52892 /* ptr may be NULL */
52893 DUK_ASSERT_DISABLE(newsize >= 0);
52894
52895#if defined(DUK_USE_VOLUNTARY_GC)
52896 /* Voluntary periodic GC (if enabled). */
52897 if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
52898 goto slowpath;
52899 }
52900#endif
52901
52902#if defined(DUK_USE_GC_TORTURE)
52903 /* Simulate alloc failure on every realloc, except when mark-and-sweep
52904 * is running.
52905 */
52906 if (heap->ms_prevent_count == 0) {
52907 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
52908 res = NULL;
52909 DUK_UNREF(res);
52910 goto slowpath;
52911 }
52912#endif
52913
52914 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
52915 if (DUK_LIKELY(res != NULL)) {
52916 return res;
52917 }
52918
52919 slowpath:
52920
52921 if (newsize == 0) {
52922 DUK_D(DUK_DPRINT("first realloc attempt returned NULL for zero size realloc, use slow path to deal with it"));
52923 } else {
52924 DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
52925 }
52926 return duk__heap_mem_realloc_slowpath(heap, ptr, newsize);
52927}
52928
52929/*
52930 * Reallocate memory with garbage collection, using a callback to provide
52931 * the current allocated pointer. This variant is used when a mark-and-sweep
52932 * (e.g. finalizers) might change the original pointer.
52933 */
52934
52935/* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */
52936DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_realloc_indirect_slowpath(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
52937 void *res;
52938 duk_small_int_t i;
52939
52940 DUK_ASSERT(heap != NULL);
52941 DUK_ASSERT(heap->realloc_func != NULL);
52942 DUK_ASSERT_DISABLE(newsize >= 0);
52943
52944 if (newsize == 0) {
52945 DUK_D(DUK_DPRINT("zero size indirect realloc in slow path, return NULL"));
52946 return NULL;
52947 }
52948
52949 DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
52950
52951#if 0
52952 /*
52953 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
52954 */
52955
52956 if (heap->ms_prevent_count != 0) {
52957 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
52958 return NULL;
52959 }
52960#endif
52961
52962 /*
52963 * Retry with several GC attempts. Initial attempts are made without
52964 * emergency mode; later attempts use emergency mode which minimizes
52965 * memory allocations forcibly.
52966 */
52967
52968 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
52969 duk_small_uint_t flags;
52970
52971#if defined(DUK_USE_DEBUG)
52972 void *ptr_pre;
52973 void *ptr_post;
52974#endif
52975
52976#if defined(DUK_USE_DEBUG)
52977 ptr_pre = cb(heap, ud);
52978#endif
52979 flags = 0;
52980 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
52981 flags |= DUK_MS_FLAG_EMERGENCY;
52982 }
52983
52984 duk_heap_mark_and_sweep(heap, flags);
52985#if defined(DUK_USE_DEBUG)
52986 ptr_post = cb(heap, ud);
52987 if (ptr_pre != ptr_post) {
52988 DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p",
52989 (void *) ptr_pre, (void *) ptr_post));
52990 }
52991#endif
52992
52993 /* Note: key issue here is to re-lookup the base pointer on every attempt.
52994 * The pointer being reallocated may change after every mark-and-sweep.
52995 */
52996
52997 DUK_ASSERT(newsize > 0);
52998 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
52999 if (res || newsize == 0) {
53000 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
53001 (long) (i + 1), (long) newsize));
53002 return res;
53003 }
53004 }
53005
53006 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
53007 return NULL;
53008}
53009
53010DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
53011 void *res;
53012
53013 DUK_ASSERT(heap != NULL);
53014 DUK_ASSERT(heap->realloc_func != NULL);
53015 DUK_ASSERT_DISABLE(newsize >= 0);
53016
53017#if defined(DUK_USE_VOLUNTARY_GC)
53018 /* Voluntary periodic GC (if enabled). */
53019 if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
53020 goto slowpath;
53021 }
53022#endif
53023
53024#if defined(DUK_USE_GC_TORTURE)
53025 /* Simulate alloc failure on every realloc, except when mark-and-sweep
53026 * is running.
53027 */
53028 if (heap->ms_prevent_count == 0) {
53029 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
53030 res = NULL;
53031 DUK_UNREF(res);
53032 goto slowpath;
53033 }
53034#endif
53035
53036 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
53037 if (DUK_LIKELY(res != NULL)) {
53038 return res;
53039 }
53040
53041 slowpath:
53042
53043 if (newsize == 0) {
53044 DUK_D(DUK_DPRINT("first indirect realloc attempt returned NULL for zero size realloc, use slow path to deal with it"));
53045 } else {
53046 DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
53047 }
53048 return duk__heap_mem_realloc_indirect_slowpath(heap, cb, ud, newsize);
53049}
53050
53051/*
53052 * Free memory
53053 */
53054
53055DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void duk_heap_mem_free(duk_heap *heap, void *ptr) {
53056 DUK_ASSERT(heap != NULL);
53057 DUK_ASSERT(heap->free_func != NULL);
53058 /* ptr may be NULL */
53059
53060 /* Must behave like a no-op with NULL and any pointer returned from
53061 * malloc/realloc with zero size.
53062 */
53063 heap->free_func(heap->heap_udata, ptr);
53064
53065 /* Never perform a GC (even voluntary) in a memory free, otherwise
53066 * all call sites doing frees would need to deal with the side effects.
53067 * No need to update voluntary GC counter either.
53068 */
53069}
53070#line 1 "duk_heap_misc.c"
53071/*
53072 * Support functions for duk_heap.
53073 */
53074
53075/* #include duk_internal.h -> already included */
53076
53077DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
53078 duk_heaphdr *root;
53079
53080 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
53081
53082 root = heap->heap_allocated;
53083#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
53084 if (root != NULL) {
53085 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
53086 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
53087 }
53088 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
53089#endif
53090 DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
53091 DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
53092 DUK_HEAPHDR_ASSERT_LINKS(heap, root);
53093 heap->heap_allocated = hdr;
53094}
53095
53096#if defined(DUK_USE_REFERENCE_COUNTING)
53097DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
53098 duk_heaphdr *prev;
53099 duk_heaphdr *next;
53100
53101 /* Strings are in string table. */
53102 DUK_ASSERT(hdr != NULL);
53103 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
53104
53105 /* Target 'hdr' must be in heap_allocated (not e.g. finalize_list).
53106 * If not, heap lists will become corrupted so assert early for it.
53107 */
53108#if defined(DUK_USE_ASSERTIONS)
53109 {
53110 duk_heaphdr *tmp;
53111 for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) {
53112 if (tmp == hdr) {
53113 break;
53114 }
53115 }
53116 DUK_ASSERT(tmp == hdr);
53117 }
53118#endif
53119
53120 /* Read/write only once to minimize pointer compression calls. */
53121 prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
53122 next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
53123
53124 if (prev != NULL) {
53125 DUK_ASSERT(heap->heap_allocated != hdr);
53126 DUK_HEAPHDR_SET_NEXT(heap, prev, next);
53127 } else {
53128 DUK_ASSERT(heap->heap_allocated == hdr);
53129 heap->heap_allocated = next;
53130 }
53131 if (next != NULL) {
53132 DUK_HEAPHDR_SET_PREV(heap, next, prev);
53133 } else {
53134 ;
53135 }
53136}
53137#endif /* DUK_USE_REFERENCE_COUNTING */
53138
53139#if defined(DUK_USE_FINALIZER_SUPPORT)
53140DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
53141 duk_heaphdr *root;
53142
53143 root = heap->finalize_list;
53144#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
53145 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
53146 if (root != NULL) {
53147 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
53148 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
53149 }
53150#endif
53151 DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
53152 DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
53153 DUK_HEAPHDR_ASSERT_LINKS(heap, root);
53154 heap->finalize_list = hdr;
53155}
53156#endif /* DUK_USE_FINALIZER_SUPPORT */
53157
53158#if defined(DUK_USE_FINALIZER_SUPPORT)
53159DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
53160#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
53161 duk_heaphdr *next;
53162 duk_heaphdr *prev;
53163
53164 next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
53165 prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
53166 if (next != NULL) {
53167 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr);
53168 DUK_HEAPHDR_SET_PREV(heap, next, prev);
53169 }
53170 if (prev == NULL) {
53171 DUK_ASSERT(hdr == heap->finalize_list);
53172 heap->finalize_list = next;
53173 } else {
53174 DUK_ASSERT(hdr != heap->finalize_list);
53175 DUK_HEAPHDR_SET_NEXT(heap, prev, next);
53176 }
53177#else
53178 duk_heaphdr *next;
53179 duk_heaphdr *curr;
53180
53181 /* Random removal is expensive: we need to locate the previous element
53182 * because we don't have a 'prev' pointer.
53183 */
53184 curr = heap->finalize_list;
53185 if (curr == hdr) {
53186 heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr);
53187 } else {
53188 DUK_ASSERT(hdr != heap->finalize_list);
53189 for (;;) {
53190 DUK_ASSERT(curr != NULL); /* Caller responsibility. */
53191
53192 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
53193 if (next == hdr) {
53194 next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
53195 DUK_HEAPHDR_SET_NEXT(heap, curr, next);
53196 break;
53197 }
53198 }
53199 }
53200#endif
53201}
53202#endif /* DUK_USE_FINALIZER_SUPPORT */
53203
53204#if defined(DUK_USE_ASSERTIONS)
53205DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) {
53206 duk_heaphdr *curr;
53207 DUK_ASSERT(heap != NULL);
53208
53209 for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
53210 if (curr == ptr) {
53211 return 1;
53212 }
53213 }
53214 return 0;
53215}
53216#endif /* DUK_USE_ASSERTIONS */
53217
53218#if defined(DUK_USE_INTERRUPT_COUNTER)
53219DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
53220 duk_hthread *curr_thr;
53221
53222 DUK_ASSERT(heap != NULL);
53223
53224 if (new_thr != NULL) {
53225 curr_thr = heap->curr_thread;
53226 if (curr_thr == NULL) {
53227 /* For initial entry use default value; zero forces an
53228 * interrupt before executing the first insturction.
53229 */
53230 DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
53231 new_thr->interrupt_counter = 0;
53232 new_thr->interrupt_init = 0;
53233 } else {
53234 /* Copy interrupt counter/init value state to new thread (if any).
53235 * It's OK for new_thr to be the same as curr_thr.
53236 */
53237#if defined(DUK_USE_DEBUG)
53238 if (new_thr != curr_thr) {
53239 DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
53240 }
53241#endif
53242 new_thr->interrupt_counter = curr_thr->interrupt_counter;
53243 new_thr->interrupt_init = curr_thr->interrupt_init;
53244 }
53245 } else {
53246 DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
53247 }
53248
53249 heap->curr_thread = new_thr; /* may be NULL */
53250}
53251#endif /* DUK_USE_INTERRUPT_COUNTER */
53252
53253#if defined(DUK_USE_ASSERTIONS)
53254DUK_INTERNAL void duk_heap_assert_valid(duk_heap *heap) {
53255 DUK_ASSERT(heap != NULL);
53256}
53257#endif
53258#line 1 "duk_heap_refcount.c"
53259/*
53260 * Reference counting implementation.
53261 *
53262 * INCREF/DECREF, finalization and freeing of objects whose refcount reaches
53263 * zero (refzero). These operations are very performance sensitive, so
53264 * various small tricks are used in an attempt to maximize speed.
53265 */
53266
53267/* #include duk_internal.h -> already included */
53268
53269#if defined(DUK_USE_REFERENCE_COUNTING)
53270
53271#if !defined(DUK_USE_DOUBLE_LINKED_HEAP)
53272#error internal error, reference counting requires a double linked heap
53273#endif
53274
53275/*
53276 * Heap object refcount finalization.
53277 *
53278 * When an object is about to be freed, all other objects it refers to must
53279 * be decref'd. Refcount finalization does NOT free the object or its inner
53280 * allocations (mark-and-sweep shares these helpers), it just manipulates
53281 * the refcounts.
53282 *
53283 * Note that any of the DECREFs may cause a refcount to drop to zero. If so,
53284 * the object won't be refzero processed inline, but will just be queued to
53285 * refzero_list and processed by an earlier caller working on refzero_list,
53286 * eliminating C recursion from even long refzero cascades. If refzero
53287 * finalization is triggered by mark-and-sweep, refzero conditions are ignored
53288 * (objects are not even queued to refzero_list) because mark-and-sweep deals
53289 * with them; refcounts are still updated so that they remain in sync with
53290 * actual references.
53291 */
53292
53293DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) {
53294 DUK_ASSERT(count == 0 || tv != NULL);
53295
53296 while (count-- > 0) {
53297 DUK_TVAL_DECREF_NORZ(thr, tv);
53298 tv++;
53299 }
53300}
53301
53302DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) {
53303 duk_hthread *thr;
53304 duk_uint_fast32_t i;
53305 duk_uint_fast32_t n;
53306 duk_propvalue *p_val;
53307 duk_tval *p_tv;
53308 duk_hstring **p_key;
53309 duk_uint8_t *p_flag;
53310 duk_hobject *h_proto;
53311
53312 DUK_ASSERT(heap != NULL);
53313 DUK_ASSERT(heap->heap_thread != NULL);
53314 DUK_ASSERT(h);
53315 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
53316
53317 thr = heap->heap_thread;
53318 DUK_ASSERT(thr != NULL);
53319
53320 p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h);
53321 p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h);
53322 p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h);
53323 n = DUK_HOBJECT_GET_ENEXT(h);
53324 while (n-- > 0) {
53325 duk_hstring *key;
53326
53327 key = p_key[n];
53328 if (DUK_UNLIKELY(key == NULL)) {
53329 continue;
53330 }
53331 DUK_HSTRING_DECREF_NORZ(thr, key);
53332 if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) {
53333 duk_hobject *h_getset;
53334 h_getset = p_val[n].a.get;
53335 DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
53336 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
53337 h_getset = p_val[n].a.set;
53338 DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
53339 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
53340 } else {
53341 duk_tval *tv_val;
53342 tv_val = &p_val[n].v;
53343 DUK_TVAL_DECREF_NORZ(thr, tv_val);
53344 }
53345 }
53346
53347 p_tv = DUK_HOBJECT_A_GET_BASE(heap, h);
53348 n = DUK_HOBJECT_GET_ASIZE(h);
53349 while (n-- > 0) {
53350 duk_tval *tv_val;
53351 tv_val = p_tv + n;
53352 DUK_TVAL_DECREF_NORZ(thr, tv_val);
53353 }
53354
53355 /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */
53356
53357 h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h);
53358 DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto));
53359 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto);
53360
53361 /* XXX: Object subclass tests are quite awkward at present, ideally
53362 * we should be able to switch-case here with a dense index (subtype
53363 * number or something). For now, fast path plain objects and arrays
53364 * and bit test the rest individually.
53365 */
53366
53367 if (DUK_HOBJECT_HAS_FASTREFS(h)) {
53368 /* Plain object or array, nothing more to do. While a
53369 * duk_harray has additional fields, none of them need
53370 * DECREF updates.
53371 */
53372 DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
53373 return;
53374 }
53375 DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
53376
53377 /* Slow path: special object, start bit checks from most likely. */
53378
53379 /* XXX: reorg, more common first */
53380 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
53381 duk_hcompfunc *f = (duk_hcompfunc *) h;
53382 duk_tval *tv, *tv_end;
53383 duk_hobject **funcs, **funcs_end;
53384
53385 DUK_HCOMPFUNC_ASSERT_VALID(f);
53386
53387 if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) {
53388 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
53389 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
53390 while (tv < tv_end) {
53391 DUK_TVAL_DECREF_NORZ(thr, tv);
53392 tv++;
53393 }
53394
53395 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
53396 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
53397 while (funcs < funcs_end) {
53398 duk_hobject *h_func;
53399 h_func = *funcs;
53400 DUK_ASSERT(h_func != NULL);
53401 DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func));
53402 DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func);
53403 funcs++;
53404 }
53405 } else {
53406 /* May happen in some out-of-memory corner cases. */
53407 DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref"));
53408 }
53409
53410 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
53411 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
53412 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f));
53413 } else if (DUK_HOBJECT_IS_DECENV(h)) {
53414 duk_hdecenv *e = (duk_hdecenv *) h;
53415 DUK_HDECENV_ASSERT_VALID(e);
53416 DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread);
53417 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap);
53418 } else if (DUK_HOBJECT_IS_OBJENV(h)) {
53419 duk_hobjenv *e = (duk_hobjenv *) h;
53420 DUK_HOBJENV_ASSERT_VALID(e);
53421 DUK_ASSERT(e->target != NULL); /* Required for object environments. */
53422 DUK_HOBJECT_DECREF_NORZ(thr, e->target);
53423#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53424 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
53425 duk_hbufobj *b = (duk_hbufobj *) h;
53426 DUK_HBUFOBJ_ASSERT_VALID(b);
53427 DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
53428 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
53429#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
53430 } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
53431 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
53432 DUK_HBOUNDFUNC_ASSERT_VALID(f);
53433 DUK_TVAL_DECREF_NORZ(thr, &f->target);
53434 DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
53435 duk__decref_tvals_norz(thr, f->args, f->nargs);
53436#if defined(DUK_USE_ES6_PROXY)
53437 } else if (DUK_HOBJECT_IS_PROXY(h)) {
53438 duk_hproxy *p = (duk_hproxy *) h;
53439 DUK_HPROXY_ASSERT_VALID(p);
53440 DUK_HOBJECT_DECREF_NORZ(thr, p->target);
53441 DUK_HOBJECT_DECREF_NORZ(thr, p->handler);
53442#endif /* DUK_USE_ES6_PROXY */
53443 } else if (DUK_HOBJECT_IS_THREAD(h)) {
53444 duk_hthread *t = (duk_hthread *) h;
53445 duk_activation *act;
53446 duk_tval *tv;
53447
53448 DUK_HTHREAD_ASSERT_VALID(t);
53449
53450 tv = t->valstack;
53451 while (tv < t->valstack_top) {
53452 DUK_TVAL_DECREF_NORZ(thr, tv);
53453 tv++;
53454 }
53455
53456 for (act = t->callstack_curr; act != NULL; act = act->parent) {
53457 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
53458 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
53459 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
53460#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
53461 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
53462#endif
53463#if 0 /* nothing now */
53464 for (cat = act->cat; cat != NULL; cat = cat->parent) {
53465 }
53466#endif
53467 }
53468
53469
53470 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
53471 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
53472 }
53473
53474 DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer);
53475 } else {
53476 /* We may come here if the object should have a FASTREFS flag
53477 * but it's missing for some reason. Assert for never getting
53478 * here; however, other than performance, this is harmless.
53479 */
53480 DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
53481 DUK_ASSERT(0);
53482 }
53483}
53484
53485DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) {
53486 DUK_ASSERT(heap != NULL);
53487 DUK_ASSERT(heap->heap_thread != NULL);
53488 DUK_ASSERT(hdr != NULL);
53489
53490 if (DUK_HEAPHDR_IS_OBJECT(hdr)) {
53491 duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr);
53492 }
53493 /* DUK_HTYPE_BUFFER: nothing to finalize */
53494 /* DUK_HTYPE_STRING: nothing to finalize */
53495}
53496
53497/*
53498 * Refzero processing for duk_hobject: queue a refzero'ed object to either
53499 * finalize_list or refzero_list and process the relevent list(s) if
53500 * necessary.
53501 *
53502 * Refzero_list is single linked, with only 'prev' pointers set and valid.
53503 * All 'next' pointers are intentionally left as garbage. This doesn't
53504 * matter because refzero_list is processed to completion before any other
53505 * code (like mark-and-sweep) might walk the list.
53506 *
53507 * In more detail:
53508 *
53509 * - On first insert refzero_list is NULL and the new object becomes the
53510 * first and only element on the list; duk__refcount_free_pending() is
53511 * called and it starts processing the list from the initial element,
53512 * i.e. the list tail.
53513 *
53514 * - As each object is refcount finalized, new objects may be queued to
53515 * refzero_list head. Their 'next' pointers are left as garbage, but
53516 * 'prev' points are set correctly, with the element at refzero_list
53517 * having a NULL 'prev' pointer. The fact that refzero_list is non-NULL
53518 * is used to reject (1) recursive duk__refcount_free_pending() and
53519 * (2) finalize_list processing calls.
53520 *
53521 * - When we're done with the current object, read its 'prev' pointer and
53522 * free the object. If 'prev' is NULL, we've reached head of list and are
53523 * done: set refzero_list to NULL and process pending finalizers. Otherwise
53524 * continue processing the list.
53525 *
53526 * A refzero cascade is free of side effects because it only involves
53527 * queueing more objects and freeing memory; finalizer execution is blocked
53528 * in the code path queueing objects to finalize_list. As a result the
53529 * initial refzero call (which triggers duk__refcount_free_pending()) must
53530 * check finalize_list so that finalizers are executed snappily.
53531 *
53532 * If finalize_list processing starts first, refzero may occur while we're
53533 * processing finalizers. That's fine: that particular refzero cascade is
53534 * handled to completion without side effects. Once the cascade is complete,
53535 * we'll run pending finalizers but notice that we're already doing that and
53536 * return.
53537 *
53538 * This could be expanded to allow incremental freeing: just bail out
53539 * early and resume at a future alloc/decref/refzero. However, if that
53540 * were done, the list structure would need to be kept consistent at all
53541 * times, mark-and-sweep would need to handle refzero_list, etc.
53542 */
53543
53544DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) {
53545 duk_heaphdr *curr;
53546#if defined(DUK_USE_DEBUG)
53547 duk_int_t count = 0;
53548#endif
53549
53550 DUK_ASSERT(heap != NULL);
53551
53552 curr = heap->refzero_list;
53553 DUK_ASSERT(curr != NULL);
53554 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL); /* We're called on initial insert only. */
53555 /* curr->next is GARBAGE. */
53556
53557 do {
53558 duk_heaphdr *prev;
53559
53560 DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr));
53561
53562#if defined(DUK_USE_DEBUG)
53563 count++;
53564#endif
53565
53566 DUK_ASSERT(curr != NULL);
53567 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
53568 /* FINALIZED may be set; don't care about flags here. */
53569
53570 /* Refcount finalize 'curr'. Refzero_list must be non-NULL
53571 * here to prevent recursive entry to duk__refcount_free_pending().
53572 */
53573 DUK_ASSERT(heap->refzero_list != NULL);
53574 duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
53575
53576 prev = DUK_HEAPHDR_GET_PREV(heap, curr);
53577 DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \
53578 (prev != NULL && heap->refzero_list != curr));
53579 /* prev->next is intentionally not updated and is garbage. */
53580
53581 duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */
53582
53583 curr = prev;
53584 } while (curr != NULL);
53585
53586 heap->refzero_list = NULL;
53587
53588 DUK_DD(DUK_DDPRINT("refzero processed %ld objects", (long) count));
53589}
53590
53591DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) {
53592 duk_heaphdr *hdr;
53593 duk_heaphdr *root;
53594
53595 DUK_ASSERT(heap != NULL);
53596 DUK_ASSERT(heap->heap_thread != NULL);
53597 DUK_ASSERT(obj != NULL);
53598 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT);
53599
53600 hdr = (duk_heaphdr *) obj;
53601
53602 /* Refzero'd objects must be in heap_allocated. They can't be in
53603 * finalize_list because all objects on finalize_list have an
53604 * artificial +1 refcount bump.
53605 */
53606#if defined(DUK_USE_ASSERTIONS)
53607 DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj));
53608#endif
53609
53610 DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr);
53611
53612#if defined(DUK_USE_FINALIZER_SUPPORT)
53613 /* This finalizer check MUST BE side effect free. It should also be
53614 * as fast as possible because it's applied to every object freed.
53615 */
53616 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) {
53617 /* Special case: FINALIZED may be set if mark-and-sweep queued
53618 * object for finalization, the finalizer was executed (and
53619 * FINALIZED set), mark-and-sweep hasn't yet processed the
53620 * object again, but its refcount drops to zero. Free without
53621 * running the finalizer again.
53622 */
53623 if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
53624 DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free"));
53625 } else {
53626 /* Set FINALIZABLE flag so that all objects on finalize_list
53627 * will have it set and are thus detectable based on the
53628 * flag alone.
53629 */
53630 DUK_HEAPHDR_SET_FINALIZABLE(hdr);
53631 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
53632
53633#if defined(DUK_USE_REFERENCE_COUNTING)
53634 /* Bump refcount on finalize_list insert so that a
53635 * refzero can never occur when an object is waiting
53636 * for its finalizer call. Refzero might otherwise
53637 * now happen because we allow duk_push_heapptr() for
53638 * objects pending finalization.
53639 */
53640 DUK_HEAPHDR_PREINC_REFCOUNT(hdr);
53641#endif
53642 DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr);
53643
53644 /* Process finalizers unless skipping is explicitly
53645 * requested (NORZ) or refzero_list is being processed
53646 * (avoids side effects during a refzero cascade).
53647 * If refzero_list is processed, the initial refzero
53648 * call will run pending finalizers when refzero_list
53649 * is done.
53650 */
53651 if (!skip_free_pending && heap->refzero_list == NULL) {
53652 duk_heap_process_finalize_list(heap);
53653 }
53654 return;
53655 }
53656 }
53657#endif /* DUK_USE_FINALIZER_SUPPORT */
53658
53659 /* No need to finalize, free object via refzero_list. */
53660
53661 root = heap->refzero_list;
53662
53663 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
53664 /* 'next' is left as GARBAGE. */
53665 heap->refzero_list = hdr;
53666
53667 if (root == NULL) {
53668 /* Object is now queued. Refzero_list was NULL so
53669 * no-one is currently processing it; do it here.
53670 * With refzero processing just doing a cascade of
53671 * free calls, we can process it directly even when
53672 * NORZ macros are used: there are no side effects.
53673 */
53674 duk__refcount_free_pending(heap);
53675 DUK_ASSERT(heap->refzero_list == NULL);
53676
53677 /* Process finalizers only after the entire cascade
53678 * is finished. In most cases there's nothing to
53679 * finalize, so fast path check to avoid a call.
53680 */
53681#if defined(DUK_USE_FINALIZER_SUPPORT)
53682 if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) {
53683 duk_heap_process_finalize_list(heap);
53684 }
53685#endif
53686 } else {
53687 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
53688 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
53689
53690 /* Object is now queued. Because refzero_list was
53691 * non-NULL, it's already being processed by someone
53692 * in the C call stack, so we're done.
53693 */
53694 }
53695}
53696
53697#if defined(DUK_USE_FINALIZER_SUPPORT)
53698DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) {
53699 DUK_ASSERT(thr != NULL);
53700 DUK_ASSERT(thr->heap != NULL);
53701 DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
53702
53703 if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
53704 duk_heap_process_finalize_list(thr->heap);
53705 }
53706}
53707
53708DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) {
53709 DUK_ASSERT(thr != NULL);
53710 DUK_ASSERT(thr->heap != NULL);
53711 DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
53712
53713 if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
53714 duk_heap_process_finalize_list(thr->heap);
53715 }
53716}
53717#endif /* DUK_USE_FINALIZER_SUPPORT */
53718
53719/*
53720 * Refzero processing for duk_hstring.
53721 */
53722
53723DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) {
53724 DUK_ASSERT(heap != NULL);
53725 DUK_ASSERT(heap->heap_thread != NULL);
53726 DUK_ASSERT(str != NULL);
53727 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING);
53728
53729 duk_heap_strcache_string_remove(heap, str);
53730 duk_heap_strtable_unlink(heap, str);
53731 duk_free_hstring(heap, str);
53732}
53733
53734/*
53735 * Refzero processing for duk_hbuffer.
53736 */
53737
53738DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) {
53739 DUK_ASSERT(heap != NULL);
53740 DUK_ASSERT(heap->heap_thread != NULL);
53741 DUK_ASSERT(buf != NULL);
53742 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER);
53743
53744 DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf);
53745 duk_free_hbuffer(heap, buf);
53746}
53747
53748/*
53749 * Incref and decref functions.
53750 *
53751 * Decref may trigger immediate refzero handling, which may free and finalize
53752 * an arbitrary number of objects (a "DECREF cascade").
53753 *
53754 * Refzero handling is skipped entirely if (1) mark-and-sweep is running or
53755 * (2) execution is paused in the debugger. The objects are left in the heap,
53756 * and will be freed by mark-and-sweep or eventual heap destruction.
53757 *
53758 * This is necessary during mark-and-sweep because refcounts are also updated
53759 * during the sweep phase (otherwise objects referenced by a swept object
53760 * would have incorrect refcounts) which then calls here. This could be
53761 * avoided by using separate decref macros in mark-and-sweep; however,
53762 * mark-and-sweep also calls finalizers which would use the ordinary decref
53763 * macros anyway.
53764 *
53765 * We can't process refzeros (= free objects) when the debugger is running
53766 * as the debugger might make an object unreachable but still continue
53767 * inspecting it (or even cause it to be pushed back). So we must rely on
53768 * mark-and-sweep to collect them.
53769 *
53770 * The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction
53771 * when running finalizers for remaining objects: the flag prevents objects
53772 * from being moved around in heap linked lists while that's being done.
53773 *
53774 * The suppress condition is important to performance.
53775 */
53776
53777#define DUK__RZ_SUPPRESS_ASSERT1() do { \
53778 DUK_ASSERT(thr != NULL); \
53779 DUK_ASSERT(thr->heap != NULL); \
53780 /* When mark-and-sweep runs, heap_thread must exist. */ \
53781 DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \
53782 /* In normal operation finalizers are executed with ms_running == 0 \
53783 * so we should never see ms_running == 1 and thr != heap_thread. \
53784 * In heap destruction finalizers are executed with ms_running != 0 \
53785 * to e.g. prevent refzero; a special value ms_running == 2 is used \
53786 * in that case so it can be distinguished from the normal runtime \
53787 * case, and allows a stronger assertion here (GH-2030). \
53788 */ \
53789 DUK_ASSERT(!(thr->heap->ms_running == 1 && thr != thr->heap->heap_thread)); \
53790 /* We may be called when the heap is initializing and we process \
53791 * refzeros normally, but mark-and-sweep and finalizers are prevented \
53792 * if that's the case. \
53793 */ \
53794 DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \
53795 DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \
53796 } while (0)
53797
53798#if defined(DUK_USE_DEBUGGER_SUPPORT)
53799#define DUK__RZ_SUPPRESS_ASSERT2() do { \
53800 /* When debugger is paused, ms_running is set. */ \
53801 DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \
53802 } while (0)
53803#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
53804#else
53805#define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0)
53806#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
53807#endif /* DUK_USE_DEBUGGER_SUPPORT */
53808
53809#define DUK__RZ_SUPPRESS_CHECK() do { \
53810 DUK__RZ_SUPPRESS_ASSERT1(); \
53811 DUK__RZ_SUPPRESS_ASSERT2(); \
53812 if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \
53813 DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \
53814 return; \
53815 } \
53816 } while (0)
53817
53818#define DUK__RZ_STRING() do { \
53819 duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \
53820 } while (0)
53821#define DUK__RZ_BUFFER() do { \
53822 duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \
53823 } while (0)
53824#define DUK__RZ_OBJECT() do { \
53825 duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \
53826 } while (0)
53827
53828/* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */
53829#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
53830#define DUK__RZ_INLINE DUK_ALWAYS_INLINE
53831#else
53832#define DUK__RZ_INLINE /*nop*/
53833#endif
53834
53835DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) {
53836 duk_heap *heap;
53837
53838 DUK_ASSERT(thr != NULL);
53839 DUK_ASSERT(h != NULL);
53840 heap = thr->heap;
53841
53842 DUK__RZ_SUPPRESS_CHECK();
53843 DUK__RZ_STRING();
53844}
53845
53846DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) {
53847 duk_heap *heap;
53848
53849 DUK_ASSERT(thr != NULL);
53850 DUK_ASSERT(h != NULL);
53851 heap = thr->heap;
53852
53853 DUK__RZ_SUPPRESS_CHECK();
53854 DUK__RZ_BUFFER();
53855}
53856
53857DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) {
53858 duk_heap *heap;
53859
53860 DUK_ASSERT(thr != NULL);
53861 DUK_ASSERT(h != NULL);
53862 heap = thr->heap;
53863
53864 DUK__RZ_SUPPRESS_CHECK();
53865 DUK__RZ_OBJECT();
53866}
53867
53868DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) {
53869 duk_heap *heap;
53870 duk_small_uint_t htype;
53871
53872 DUK_ASSERT(thr != NULL);
53873 DUK_ASSERT(h != NULL);
53874 heap = thr->heap;
53875
53876 htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h);
53877 DUK_DDD(DUK_DDDPRINT("ms_running=%ld, heap_thread=%p", (long) thr->heap->ms_running, thr->heap->heap_thread));
53878 DUK__RZ_SUPPRESS_CHECK();
53879
53880 switch (htype) {
53881 case DUK_HTYPE_STRING:
53882 /* Strings have no internal references but do have "weak"
53883 * references in the string cache. Also note that strings
53884 * are not on the heap_allocated list like other heap
53885 * elements.
53886 */
53887
53888 DUK__RZ_STRING();
53889 break;
53890
53891 case DUK_HTYPE_OBJECT:
53892 /* Objects have internal references. Must finalize through
53893 * the "refzero" work list.
53894 */
53895
53896 DUK__RZ_OBJECT();
53897 break;
53898
53899 default:
53900 /* Buffers have no internal references. However, a dynamic
53901 * buffer has a separate allocation for the buffer. This is
53902 * freed by duk_heap_free_heaphdr_raw().
53903 */
53904
53905 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER);
53906 DUK__RZ_BUFFER();
53907 break;
53908 }
53909}
53910
53911DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
53912 duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/);
53913}
53914
53915DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) {
53916 duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/);
53917}
53918
53919DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) {
53920 duk__hstring_refzero_helper(thr, h);
53921}
53922
53923DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) {
53924 duk__hbuffer_refzero_helper(thr, h);
53925}
53926
53927DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) {
53928 duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/);
53929}
53930
53931DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) {
53932 duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/);
53933}
53934
53935#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
53936DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
53937 DUK_ASSERT(tv != NULL);
53938
53939 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
53940 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
53941 DUK_ASSERT(h != NULL);
53942 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
53943 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
53944 DUK_HEAPHDR_PREINC_REFCOUNT(h);
53945 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0); /* No wrapping. */
53946 }
53947}
53948
53949DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
53950 DUK_ASSERT(thr != NULL);
53951 DUK_ASSERT(tv != NULL);
53952
53953 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
53954 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
53955 DUK_ASSERT(h != NULL);
53956 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
53957 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
53958#if 0
53959 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
53960 return;
53961 }
53962 duk_heaphdr_refzero(thr, h);
53963#else
53964 duk_heaphdr_decref(thr, h);
53965#endif
53966 }
53967}
53968
53969DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) {
53970 DUK_ASSERT(thr != NULL);
53971 DUK_ASSERT(tv != NULL);
53972
53973 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
53974 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
53975 DUK_ASSERT(h != NULL);
53976 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
53977 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
53978#if 0
53979 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
53980 return;
53981 }
53982 duk_heaphdr_refzero_norz(thr, h);
53983#else
53984 duk_heaphdr_decref_norz(thr, h);
53985#endif
53986 }
53987}
53988#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
53989
53990#define DUK__DECREF_ASSERTS() do { \
53991 DUK_ASSERT(thr != NULL); \
53992 DUK_ASSERT(thr->heap != NULL); \
53993 DUK_ASSERT(h != NULL); \
53994 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \
53995 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \
53996 } while (0)
53997#if defined(DUK_USE_ROM_OBJECTS)
53998#define DUK__INCREF_SHARED() do { \
53999 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
54000 return; \
54001 } \
54002 DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
54003 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
54004 } while (0)
54005#define DUK__DECREF_SHARED() do { \
54006 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
54007 return; \
54008 } \
54009 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
54010 return; \
54011 } \
54012 } while (0)
54013#else
54014#define DUK__INCREF_SHARED() do { \
54015 DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
54016 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
54017 } while (0)
54018#define DUK__DECREF_SHARED() do { \
54019 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
54020 return; \
54021 } \
54022 } while (0)
54023#endif
54024
54025#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
54026/* This will in practice be inlined because it's just an INC instructions
54027 * and a bit test + INC when ROM objects are enabled.
54028 */
54029DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
54030 DUK_ASSERT(h != NULL);
54031 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
54032 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
54033
54034 DUK__INCREF_SHARED();
54035}
54036
54037DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
54038 DUK__DECREF_ASSERTS();
54039 DUK__DECREF_SHARED();
54040 duk_heaphdr_refzero(thr, h);
54041
54042 /* Forced mark-and-sweep when GC torture enabled; this could happen
54043 * on any DECREF (but not DECREF_NORZ).
54044 */
54045 DUK_GC_TORTURE(thr->heap);
54046}
54047DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) {
54048 DUK__DECREF_ASSERTS();
54049 DUK__DECREF_SHARED();
54050 duk_heaphdr_refzero_norz(thr, h);
54051}
54052#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
54053
54054#if 0 /* Not needed. */
54055DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) {
54056 DUK__DECREF_ASSERTS();
54057 DUK__DECREF_SHARED();
54058 duk_hstring_refzero(thr, h);
54059}
54060DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) {
54061 DUK__DECREF_ASSERTS();
54062 DUK__DECREF_SHARED();
54063 duk_hstring_refzero_norz(thr, h);
54064}
54065DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) {
54066 DUK__DECREF_ASSERTS();
54067 DUK__DECREF_SHARED();
54068 duk_hbuffer_refzero(thr, h);
54069}
54070DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) {
54071 DUK__DECREF_ASSERTS();
54072 DUK__DECREF_SHARED();
54073 duk_hbuffer_refzero_norz(thr, h);
54074}
54075DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) {
54076 DUK__DECREF_ASSERTS();
54077 DUK__DECREF_SHARED();
54078 duk_hobject_refzero(thr, h);
54079}
54080DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
54081 DUK__DECREF_ASSERTS();
54082 DUK__DECREF_SHARED();
54083 duk_hobject_refzero_norz(thr, h);
54084}
54085#endif
54086
54087#else /* DUK_USE_REFERENCE_COUNTING */
54088
54089/* no refcounting */
54090
54091#endif /* DUK_USE_REFERENCE_COUNTING */
54092
54093/* automatic undefs */
54094#undef DUK__DECREF_ASSERTS
54095#undef DUK__DECREF_SHARED
54096#undef DUK__INCREF_SHARED
54097#undef DUK__RZ_BUFFER
54098#undef DUK__RZ_INLINE
54099#undef DUK__RZ_OBJECT
54100#undef DUK__RZ_STRING
54101#undef DUK__RZ_SUPPRESS_ASSERT1
54102#undef DUK__RZ_SUPPRESS_ASSERT2
54103#undef DUK__RZ_SUPPRESS_CHECK
54104#undef DUK__RZ_SUPPRESS_COND
54105#line 1 "duk_heap_stringcache.c"
54106/*
54107 * String cache.
54108 *
54109 * Provides a cache to optimize indexed string lookups. The cache keeps
54110 * track of (byte offset, char offset) states for a fixed number of strings.
54111 * Otherwise we'd need to scan from either end of the string, as we store
54112 * strings in (extended) UTF-8.
54113 */
54114
54115/* #include duk_internal.h -> already included */
54116
54117/*
54118 * Delete references to given hstring from the heap string cache.
54119 *
54120 * String cache references are 'weak': they are not counted towards
54121 * reference counts, nor serve as roots for mark-and-sweep. When an
54122 * object is about to be freed, such references need to be removed.
54123 */
54124
54125DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
54126 duk_uint_t i;
54127 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
54128 duk_strcache_entry *c = heap->strcache + i;
54129 if (c->h == h) {
54130 DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
54131 (void *) h, (void *) heap));
54132 c->h = NULL;
54133
54134 /* XXX: the string shouldn't appear twice, but we now loop to the
54135 * end anyway; if fixed, add a looping assertion to ensure there
54136 * is no duplicate.
54137 */
54138 }
54139 }
54140}
54141
54142/*
54143 * String scanning helpers
54144 *
54145 * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
54146 * considered to contribute a character. This must match how string
54147 * character length is computed.
54148 */
54149
54150DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
54151 while (n > 0) {
54152 for (;;) {
54153 p++;
54154 if (p >= q) {
54155 return NULL;
54156 }
54157 if ((*p & 0xc0) != 0x80) {
54158 break;
54159 }
54160 }
54161 n--;
54162 }
54163 return p;
54164}
54165
54166DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
54167 while (n > 0) {
54168 for (;;) {
54169 p--;
54170 if (p < q) {
54171 return NULL;
54172 }
54173 if ((*p & 0xc0) != 0x80) {
54174 break;
54175 }
54176 }
54177 n--;
54178 }
54179 return p;
54180}
54181
54182/*
54183 * Convert char offset to byte offset
54184 *
54185 * Avoid using the string cache if possible: for ASCII strings byte and
54186 * char offsets are equal and for short strings direct scanning may be
54187 * better than using the string cache (which may evict a more important
54188 * entry).
54189 *
54190 * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
54191 * Better typing might be to use duk_size_t.
54192 *
54193 * Caller should ensure 'char_offset' is within the string bounds [0,charlen]
54194 * (endpoint is inclusive). If this is not the case, no memory unsafe
54195 * behavior will happen but an error will be thrown.
54196 */
54197
54198DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
54199 duk_heap *heap;
54200 duk_strcache_entry *sce;
54201 duk_uint_fast32_t byte_offset;
54202 duk_uint_t i;
54203 duk_bool_t use_cache;
54204 duk_uint_fast32_t dist_start, dist_end, dist_sce;
54205 duk_uint_fast32_t char_length;
54206 const duk_uint8_t *p_start;
54207 const duk_uint8_t *p_end;
54208 const duk_uint8_t *p_found;
54209
54210 /*
54211 * For ASCII strings, the answer is simple.
54212 */
54213
54214 if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
54215 return char_offset;
54216 }
54217
54218 char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h);
54219 DUK_ASSERT(char_offset <= char_length);
54220
54221 if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
54222 /* Must recheck because the 'is ascii' flag may be set
54223 * lazily. Alternatively, we could just compare charlen
54224 * to bytelen.
54225 */
54226 return char_offset;
54227 }
54228
54229 /*
54230 * For non-ASCII strings, we need to scan forwards or backwards
54231 * from some starting point. The starting point may be the start
54232 * or end of the string, or some cached midpoint in the string
54233 * cache.
54234 *
54235 * For "short" strings we simply scan without checking or updating
54236 * the cache. For longer strings we check and update the cache as
54237 * necessary, inserting a new cache entry if none exists.
54238 */
54239
54240 DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
54241 (void *) h, (long) char_offset,
54242 (long) DUK_HSTRING_GET_CHARLEN(h),
54243 (long) DUK_HSTRING_GET_BYTELEN(h)));
54244
54245 heap = thr->heap;
54246 sce = NULL;
54247 use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
54248
54249 if (use_cache) {
54250#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
54251 DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
54252 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
54253 duk_strcache_entry *c = heap->strcache + i;
54254 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
54255 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
54256 }
54257#endif
54258
54259 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
54260 duk_strcache_entry *c = heap->strcache + i;
54261
54262 if (c->h == h) {
54263 sce = c;
54264 break;
54265 }
54266 }
54267 }
54268
54269 /*
54270 * Scan from shortest distance:
54271 * - start of string
54272 * - end of string
54273 * - cache entry (if exists)
54274 */
54275
54276 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
54277 dist_start = char_offset;
54278 dist_end = char_length - char_offset;
54279 dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
54280
54281 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
54282 p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
54283 p_found = NULL;
54284
54285 if (sce) {
54286 if (char_offset >= sce->cidx) {
54287 dist_sce = char_offset - sce->cidx;
54288 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
54289 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
54290 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
54291 "scan forwards from sce",
54292 (long) use_cache, (void *) (sce ? sce->h : NULL),
54293 (sce ? (long) sce->cidx : (long) -1),
54294 (sce ? (long) sce->bidx : (long) -1),
54295 (long) dist_start, (long) dist_end, (long) dist_sce));
54296
54297 p_found = duk__scan_forwards(p_start + sce->bidx,
54298 p_end,
54299 dist_sce);
54300 goto scan_done;
54301 }
54302 } else {
54303 dist_sce = sce->cidx - char_offset;
54304 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
54305 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
54306 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
54307 "scan backwards from sce",
54308 (long) use_cache, (void *) (sce ? sce->h : NULL),
54309 (sce ? (long) sce->cidx : (long) -1),
54310 (sce ? (long) sce->bidx : (long) -1),
54311 (long) dist_start, (long) dist_end, (long) dist_sce));
54312
54313 p_found = duk__scan_backwards(p_start + sce->bidx,
54314 p_start,
54315 dist_sce);
54316 goto scan_done;
54317 }
54318 }
54319 }
54320
54321 /* no sce, or sce scan not best */
54322
54323 if (dist_start <= dist_end) {
54324 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
54325 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
54326 "scan forwards from string start",
54327 (long) use_cache, (void *) (sce ? sce->h : NULL),
54328 (sce ? (long) sce->cidx : (long) -1),
54329 (sce ? (long) sce->bidx : (long) -1),
54330 (long) dist_start, (long) dist_end, (long) dist_sce));
54331
54332 p_found = duk__scan_forwards(p_start,
54333 p_end,
54334 dist_start);
54335 } else {
54336 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
54337 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
54338 "scan backwards from string end",
54339 (long) use_cache, (void *) (sce ? sce->h : NULL),
54340 (sce ? (long) sce->cidx : (long) -1),
54341 (sce ? (long) sce->bidx : (long) -1),
54342 (long) dist_start, (long) dist_end, (long) dist_sce));
54343
54344 p_found = duk__scan_backwards(p_end,
54345 p_start,
54346 dist_end);
54347 }
54348
54349 scan_done:
54350
54351 if (DUK_UNLIKELY(p_found == NULL)) {
54352 /* Scan error: this shouldn't normally happen; it could happen if
54353 * string is not valid UTF-8 data, and clen/blen are not consistent
54354 * with the scanning algorithm.
54355 */
54356 goto scan_error;
54357 }
54358
54359 DUK_ASSERT(p_found >= p_start);
54360 DUK_ASSERT(p_found <= p_end); /* may be equal */
54361 byte_offset = (duk_uint32_t) (p_found - p_start);
54362
54363 DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
54364 (void *) h, (long) char_offset, (long) byte_offset));
54365
54366 /*
54367 * Update cache entry (allocating if necessary), and move the
54368 * cache entry to the first place (in an "LRU" policy).
54369 */
54370
54371 if (use_cache) {
54372 /* update entry, allocating if necessary */
54373 if (!sce) {
54374 sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
54375 sce->h = h;
54376 }
54377 DUK_ASSERT(sce != NULL);
54378 sce->bidx = (duk_uint32_t) (p_found - p_start);
54379 sce->cidx = (duk_uint32_t) char_offset;
54380
54381 /* LRU: move our entry to first */
54382 if (sce > &heap->strcache[0]) {
54383 /*
54384 * A C
54385 * B A
54386 * C <- sce ==> B
54387 * D D
54388 */
54389 duk_strcache_entry tmp;
54390
54391 tmp = *sce;
54392 duk_memmove((void *) (&heap->strcache[1]),
54393 (const void *) (&heap->strcache[0]),
54394 (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
54395 heap->strcache[0] = tmp;
54396
54397 /* 'sce' points to the wrong entry here, but is no longer used */
54398 }
54399#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
54400 DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
54401 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
54402 duk_strcache_entry *c = heap->strcache + i;
54403 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
54404 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
54405 }
54406#endif
54407 }
54408
54409 return byte_offset;
54410
54411 scan_error:
54412 DUK_ERROR_INTERNAL(thr);
54413 DUK_WO_NORETURN(return 0;);
54414}
54415#line 1 "duk_heap_stringtable.c"
54416/*
54417 * Heap string table handling, string interning.
54418 */
54419
54420/* #include duk_internal.h -> already included */
54421
54422/* Resize checks not needed if minsize == maxsize, typical for low memory
54423 * targets.
54424 */
54425#define DUK__STRTAB_RESIZE_CHECK
54426#if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE)
54427#undef DUK__STRTAB_RESIZE_CHECK
54428#endif
54429
54430#if defined(DUK_USE_STRTAB_PTRCOMP)
54431#define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr))
54432#define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val))
54433#define DUK__GET_STRTABLE(heap) ((heap)->strtable16)
54434#else
54435#define DUK__HEAPPTR_ENC16(heap,ptr) (ptr)
54436#define DUK__HEAPPTR_DEC16(heap,val) (val)
54437#define DUK__GET_STRTABLE(heap) ((heap)->strtable)
54438#endif
54439
54440#define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
54441
54442/*
54443 * Debug dump stringtable.
54444 */
54445
54446#if defined(DUK_USE_DEBUG)
54447DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) {
54448#if defined(DUK_USE_STRTAB_PTRCOMP)
54449 duk_uint16_t *strtable;
54450#else
54451 duk_hstring **strtable;
54452#endif
54453 duk_uint32_t i;
54454 duk_hstring *h;
54455 duk_size_t count_total = 0;
54456 duk_size_t count_chain;
54457 duk_size_t count_chain_min = DUK_SIZE_MAX;
54458 duk_size_t count_chain_max = 0;
54459 duk_size_t count_len[8]; /* chain lengths from 0 to 7 */
54460
54461 if (heap == NULL) {
54462 DUK_D(DUK_DPRINT("string table, heap=NULL"));
54463 return;
54464 }
54465
54466 strtable = DUK__GET_STRTABLE(heap);
54467 if (strtable == NULL) {
54468 DUK_D(DUK_DPRINT("string table, strtab=NULL"));
54469 return;
54470 }
54471
54472 duk_memzero((void *) count_len, sizeof(count_len));
54473 for (i = 0; i < heap->st_size; i++) {
54474 h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
54475 count_chain = 0;
54476 while (h != NULL) {
54477 count_chain++;
54478 h = h->hdr.h_next;
54479 }
54480 if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) {
54481 count_len[count_chain]++;
54482 }
54483 count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max);
54484 count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min);
54485 count_total += count_chain;
54486 }
54487
54488 DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: "
54489 "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...",
54490 (void *) heap->strtable, (unsigned long) count_total,
54491 (unsigned long) count_chain_min, (unsigned long) count_chain_max,
54492 (double) count_total / (double) heap->st_size,
54493 (unsigned long) count_len[0], (unsigned long) count_len[1],
54494 (unsigned long) count_len[2], (unsigned long) count_len[3],
54495 (unsigned long) count_len[4], (unsigned long) count_len[5],
54496 (unsigned long) count_len[6], (unsigned long) count_len[7]));
54497}
54498#endif /* DUK_USE_DEBUG */
54499
54500/*
54501 * Assertion helper to ensure strtable is populated correctly.
54502 */
54503
54504#if defined(DUK_USE_ASSERTIONS)
54505DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) {
54506#if defined(DUK_USE_STRTAB_PTRCOMP)
54507 duk_uint16_t *strtable;
54508#else
54509 duk_hstring **strtable;
54510#endif
54511 duk_uint32_t i;
54512 duk_hstring *h;
54513 duk_size_t count = 0;
54514
54515 DUK_ASSERT(heap != NULL);
54516
54517 strtable = DUK__GET_STRTABLE(heap);
54518 if (strtable != NULL) {
54519 DUK_ASSERT(heap->st_size != 0);
54520 DUK_ASSERT(heap->st_mask == heap->st_size - 1);
54521
54522 for (i = 0; i < heap->st_size; i++) {
54523 h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
54524 while (h != NULL) {
54525 DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
54526 count++;
54527 h = h->hdr.h_next;
54528 }
54529 }
54530 } else {
54531 DUK_ASSERT(heap->st_size == 0);
54532 DUK_ASSERT(heap->st_mask == 0);
54533 }
54534
54535#if defined(DUK__STRTAB_RESIZE_CHECK)
54536 DUK_ASSERT(count == (duk_size_t) heap->st_count);
54537#endif
54538}
54539#endif /* DUK_USE_ASSERTIONS */
54540
54541/*
54542 * Allocate and initialize a duk_hstring.
54543 *
54544 * Returns a NULL if allocation or initialization fails for some reason.
54545 *
54546 * The string won't be inserted into the string table and isn't tracked in
54547 * any way (link pointers will be NULL). The caller must place the string
54548 * into the string table without any risk of a longjmp, otherwise the string
54549 * is leaked.
54550 */
54551
54552DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
54553 const duk_uint8_t *str,
54554 duk_uint32_t blen,
54555 duk_uint32_t strhash,
54556 const duk_uint8_t *extdata) {
54557 duk_hstring *res;
54558 const duk_uint8_t *data;
54559#if !defined(DUK_USE_HSTRING_ARRIDX)
54560 duk_uarridx_t dummy;
54561#endif
54562
54563 DUK_ASSERT(heap != NULL);
54564 DUK_UNREF(extdata);
54565
54566#if defined(DUK_USE_STRLEN16)
54567 /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
54568 if (blen > 0xffffUL) {
54569 DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
54570 goto alloc_error;
54571 }
54572#endif
54573
54574 /* XXX: Memzeroing the allocated structure is not really necessary
54575 * because we could just initialize all fields explicitly (almost
54576 * all fields are initialized explicitly anyway).
54577 */
54578#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
54579 if (extdata) {
54580 res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external));
54581 if (DUK_UNLIKELY(res == NULL)) {
54582 goto alloc_error;
54583 }
54584 duk_memzero(res, sizeof(duk_hstring_external));
54585#if defined(DUK_USE_EXPLICIT_NULL_INIT)
54586 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
54587#endif
54588 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
54589
54590 DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */
54591 data = extdata;
54592 ((duk_hstring_external *) res)->extdata = extdata;
54593 } else
54594#endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */
54595 {
54596 duk_uint8_t *data_tmp;
54597
54598 /* NUL terminate for convenient C access */
54599 DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */
54600 res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1);
54601 if (DUK_UNLIKELY(res == NULL)) {
54602 goto alloc_error;
54603 }
54604 duk_memzero(res, sizeof(duk_hstring));
54605#if defined(DUK_USE_EXPLICIT_NULL_INIT)
54606 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
54607#endif
54608 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
54609
54610 data_tmp = (duk_uint8_t *) (res + 1);
54611 duk_memcpy(data_tmp, str, blen);
54612 data_tmp[blen] = (duk_uint8_t) 0;
54613 data = (const duk_uint8_t *) data_tmp;
54614 }
54615
54616 DUK_HSTRING_SET_BYTELEN(res, blen);
54617 DUK_HSTRING_SET_HASH(res, strhash);
54618
54619 DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
54620#if defined(DUK_USE_HSTRING_ARRIDX)
54621 res->arridx = duk_js_to_arrayindex_string(data, blen);
54622 if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) {
54623#else
54624 dummy = duk_js_to_arrayindex_string(data, blen);
54625 if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) {
54626#endif
54627 /* Array index strings cannot be symbol strings,
54628 * and they're always pure ASCII so blen == clen.
54629 */
54630 DUK_HSTRING_SET_ARRIDX(res);
54631 DUK_HSTRING_SET_ASCII(res);
54632 DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen);
54633 } else {
54634 /* Because 'data' is NUL-terminated, we don't need a
54635 * blen > 0 check here. For NUL (0x00) the symbol
54636 * checks will be false.
54637 */
54638 if (DUK_UNLIKELY(data[0] >= 0x80U)) {
54639 if (data[0] <= 0x81) {
54640 DUK_HSTRING_SET_SYMBOL(res);
54641 } else if (data[0] == 0x82U || data[0] == 0xffU) {
54642 DUK_HSTRING_SET_HIDDEN(res);
54643 DUK_HSTRING_SET_SYMBOL(res);
54644 }
54645 }
54646
54647 /* Using an explicit 'ASCII' flag has larger footprint (one call site
54648 * only) but is quite useful for the case when there's no explicit
54649 * 'clen' in duk_hstring.
54650 *
54651 * The flag is set lazily for RAM strings.
54652 */
54653 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
54654
54655#if defined(DUK_USE_HSTRING_LAZY_CLEN)
54656 /* Charlen initialized to 0, updated on-the-fly. */
54657#else
54658 duk_hstring_init_charlen(res); /* Also sets ASCII flag. */
54659#endif
54660 }
54661
54662 DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld",
54663 (unsigned long) DUK_HSTRING_GET_HASH(res),
54664 (long) DUK_HSTRING_GET_BYTELEN(res),
54665 (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
54666 (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
54667
54668 DUK_ASSERT(res != NULL);
54669 return res;
54670
54671 alloc_error:
54672 return NULL;
54673}
54674
54675/*
54676 * Grow strtable allocation in-place.
54677 */
54678
54679#if defined(DUK__STRTAB_RESIZE_CHECK)
54680DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) {
54681 duk_uint32_t new_st_size;
54682 duk_uint32_t old_st_size;
54683 duk_uint32_t i;
54684 duk_hstring *h;
54685 duk_hstring *next;
54686 duk_hstring *prev;
54687#if defined(DUK_USE_STRTAB_PTRCOMP)
54688 duk_uint16_t *new_ptr;
54689 duk_uint16_t *new_ptr_high;
54690#else
54691 duk_hstring **new_ptr;
54692 duk_hstring **new_ptr_high;
54693#endif
54694
54695 DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
54696
54697 DUK_ASSERT(heap != NULL);
54698 DUK_ASSERT(heap->st_resizing == 1);
54699 DUK_ASSERT(heap->st_size >= 2);
54700 DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
54701 DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
54702
54703 DUK_STATS_INC(heap, stats_strtab_resize_grow);
54704
54705 new_st_size = heap->st_size << 1U;
54706 DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */
54707
54708 /* Reallocate the strtable first and then work in-place to rehash
54709 * strings. We don't need an indirect allocation here: even if GC
54710 * is triggered to satisfy the allocation, recursive strtable resize
54711 * is prevented by flags. This is also why we don't need to use
54712 * DUK_REALLOC_INDIRECT().
54713 */
54714
54715#if defined(DUK_USE_STRTAB_PTRCOMP)
54716 new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
54717#else
54718 new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
54719#endif
54720 if (DUK_UNLIKELY(new_ptr == NULL)) {
54721 /* If realloc fails we can continue normally: the string table
54722 * won't "fill up" although chains will gradually get longer.
54723 * When string insertions continue, we'll quite soon try again
54724 * with no special handling.
54725 */
54726 DUK_D(DUK_DPRINT("string table grow failed, ignoring"));
54727 return;
54728 }
54729#if defined(DUK_USE_STRTAB_PTRCOMP)
54730 heap->strtable16 = new_ptr;
54731#else
54732 heap->strtable = new_ptr;
54733#endif
54734
54735 /* Rehash a single bucket into two separate ones. When we grow
54736 * by x2 the highest 'new' bit determines whether a string remains
54737 * in its old position (bit is 0) or goes to a new one (bit is 1).
54738 */
54739
54740 old_st_size = heap->st_size;
54741 new_ptr_high = new_ptr + old_st_size;
54742 for (i = 0; i < old_st_size; i++) {
54743 duk_hstring *new_root;
54744 duk_hstring *new_root_high;
54745
54746 h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]);
54747 new_root = h;
54748 new_root_high = NULL;
54749
54750 prev = NULL;
54751 while (h != NULL) {
54752 duk_uint32_t mask;
54753
54754 DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
54755 next = h->hdr.h_next;
54756
54757 /* Example: if previous size was 256, previous mask is 0xFF
54758 * and size is 0x100 which corresponds to the new bit that
54759 * comes into play.
54760 */
54761 DUK_ASSERT(heap->st_mask == old_st_size - 1);
54762 mask = old_st_size;
54763 if (DUK_HSTRING_GET_HASH(h) & mask) {
54764 if (prev != NULL) {
54765 prev->hdr.h_next = h->hdr.h_next;
54766 } else {
54767 DUK_ASSERT(h == new_root);
54768 new_root = h->hdr.h_next;
54769 }
54770
54771 h->hdr.h_next = new_root_high;
54772 new_root_high = h;
54773 } else {
54774 prev = h;
54775 }
54776 h = next;
54777 }
54778
54779 new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root);
54780 new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high);
54781 }
54782
54783 heap->st_size = new_st_size;
54784 heap->st_mask = new_st_size - 1;
54785
54786#if defined(DUK_USE_ASSERTIONS)
54787 duk__strtable_assert_checks(heap);
54788#endif
54789}
54790#endif /* DUK__STRTAB_RESIZE_CHECK */
54791
54792/*
54793 * Shrink strtable allocation in-place.
54794 */
54795
54796#if defined(DUK__STRTAB_RESIZE_CHECK)
54797DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) {
54798 duk_uint32_t new_st_size;
54799 duk_uint32_t i;
54800 duk_hstring *h;
54801 duk_hstring *other;
54802 duk_hstring *root;
54803#if defined(DUK_USE_STRTAB_PTRCOMP)
54804 duk_uint16_t *old_ptr;
54805 duk_uint16_t *old_ptr_high;
54806 duk_uint16_t *new_ptr;
54807#else
54808 duk_hstring **old_ptr;
54809 duk_hstring **old_ptr_high;
54810 duk_hstring **new_ptr;
54811#endif
54812
54813 DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
54814
54815 DUK_ASSERT(heap != NULL);
54816 DUK_ASSERT(heap->st_resizing == 1);
54817 DUK_ASSERT(heap->st_size >= 2);
54818 DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */
54819 DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
54820
54821 DUK_STATS_INC(heap, stats_strtab_resize_shrink);
54822
54823 new_st_size = heap->st_size >> 1U;
54824
54825 /* Combine two buckets into a single one. When we shrink, one hash
54826 * bit (highest) disappears.
54827 */
54828 old_ptr = DUK__GET_STRTABLE(heap);
54829 old_ptr_high = old_ptr + new_st_size;
54830 for (i = 0; i < new_st_size; i++) {
54831 h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]);
54832 other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]);
54833
54834 if (h == NULL) {
54835 /* First chain is empty, so use second one as is. */
54836 root = other;
54837 } else {
54838 /* Find end of first chain, and link in the second. */
54839 root = h;
54840 while (h->hdr.h_next != NULL) {
54841 h = h->hdr.h_next;
54842 }
54843 h->hdr.h_next = other;
54844 }
54845
54846 old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root);
54847 }
54848
54849 heap->st_size = new_st_size;
54850 heap->st_mask = new_st_size - 1;
54851
54852 /* The strtable is now consistent and we can realloc safely. Even
54853 * if side effects cause string interning or removal the strtable
54854 * updates are safe. Recursive resize has been prevented by caller.
54855 * This is also why we don't need to use DUK_REALLOC_INDIRECT().
54856 *
54857 * We assume a realloc() to a smaller size is guaranteed to succeed.
54858 * It would be relatively straightforward to handle the error by
54859 * essentially performing a "grow" step to recover.
54860 */
54861
54862#if defined(DUK_USE_STRTAB_PTRCOMP)
54863 new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
54864 DUK_ASSERT(new_ptr != NULL);
54865 heap->strtable16 = new_ptr;
54866#else
54867 new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
54868 DUK_ASSERT(new_ptr != NULL);
54869 heap->strtable = new_ptr;
54870#endif
54871
54872#if defined(DUK_USE_ASSERTIONS)
54873 duk__strtable_assert_checks(heap);
54874#endif
54875}
54876#endif /* DUK__STRTAB_RESIZE_CHECK */
54877
54878/*
54879 * Grow/shrink check.
54880 */
54881
54882#if defined(DUK__STRTAB_RESIZE_CHECK)
54883DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) {
54884 duk_uint32_t load_factor; /* fixed point */
54885
54886 DUK_ASSERT(heap != NULL);
54887#if defined(DUK_USE_STRTAB_PTRCOMP)
54888 DUK_ASSERT(heap->strtable16 != NULL);
54889#else
54890 DUK_ASSERT(heap->strtable != NULL);
54891#endif
54892
54893 DUK_STATS_INC(heap, stats_strtab_resize_check);
54894
54895 /* Prevent recursive resizing. */
54896 if (DUK_UNLIKELY(heap->st_resizing != 0U)) {
54897 DUK_D(DUK_DPRINT("prevent recursive strtable resize"));
54898 return;
54899 }
54900
54901 heap->st_resizing = 1;
54902
54903 DUK_ASSERT(heap->st_size >= 16U);
54904 DUK_ASSERT((heap->st_size >> 4U) >= 1);
54905 load_factor = heap->st_count / (heap->st_size >> 4U);
54906
54907 DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)",
54908 (unsigned long) heap->st_size, (unsigned long) heap->st_count,
54909 (unsigned long) load_factor,
54910 (double) heap->st_count / (double) heap->st_size));
54911
54912 if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) {
54913 if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) {
54914 DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size"));
54915 } else {
54916 DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
54917#if defined(DUK_USE_DEBUG)
54918 duk_heap_strtable_dump(heap);
54919#endif
54920 duk__strtable_grow_inplace(heap);
54921 }
54922 } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) {
54923 if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) {
54924 DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size"));
54925 } else {
54926 DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
54927#if defined(DUK_USE_DEBUG)
54928 duk_heap_strtable_dump(heap);
54929#endif
54930 duk__strtable_shrink_inplace(heap);
54931 }
54932 } else {
54933 DUK_DD(DUK_DDPRINT("no need for strtable resize"));
54934 }
54935
54936 heap->st_resizing = 0;
54937}
54938#endif /* DUK__STRTAB_RESIZE_CHECK */
54939
54940/*
54941 * Torture grow/shrink: unconditionally grow and shrink back.
54942 */
54943
54944#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
54945DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) {
54946 duk_uint32_t old_st_size;
54947
54948 DUK_ASSERT(heap != NULL);
54949
54950 old_st_size = heap->st_size;
54951 if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) {
54952 return;
54953 }
54954
54955 heap->st_resizing = 1;
54956 duk__strtable_grow_inplace(heap);
54957 if (heap->st_size > old_st_size) {
54958 duk__strtable_shrink_inplace(heap);
54959 }
54960 heap->st_resizing = 0;
54961}
54962#endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */
54963
54964/*
54965 * Raw intern; string already checked not to be present.
54966 */
54967
54968DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
54969 duk_hstring *res;
54970 const duk_uint8_t *extdata;
54971#if defined(DUK_USE_STRTAB_PTRCOMP)
54972 duk_uint16_t *slot;
54973#else
54974 duk_hstring **slot;
54975#endif
54976
54977 DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf",
54978 (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash,
54979 (unsigned long) heap->st_size, (unsigned long) heap->st_count,
54980 (double) heap->st_count / (double) heap->st_size));
54981
54982 DUK_ASSERT(heap != NULL);
54983
54984 /* Prevent any side effects on the string table and the caller provided
54985 * str/blen arguments while interning is in progress. For example, if
54986 * the caller provided str/blen from a dynamic buffer, a finalizer
54987 * might resize or modify that dynamic buffer, invalidating the call
54988 * arguments.
54989 *
54990 * While finalizers must be prevented, mark-and-sweep itself is fine.
54991 * Recursive string table resize is prevented explicitly here.
54992 */
54993
54994 heap->pf_prevent_count++;
54995 DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */
54996
54997#if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
54998 duk__strtable_resize_torture(heap);
54999#endif
55000
55001 /* String table grow/shrink check. Because of chaining (and no
55002 * accumulation issues as with hash probe chains and DELETED
55003 * markers) there's never a mandatory need to resize right now.
55004 * Check for the resize only periodically, based on st_count
55005 * bit pattern. Because string table removal doesn't do a shrink
55006 * check, we do that also here.
55007 *
55008 * Do the resize and possible grow/shrink before the new duk_hstring
55009 * has been allocated. Otherwise we may trigger a GC when the result
55010 * duk_hstring is not yet strongly referenced.
55011 */
55012
55013#if defined(DUK__STRTAB_RESIZE_CHECK)
55014 if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) {
55015 duk__strtable_resize_check(heap);
55016 }
55017#endif
55018
55019 /* External string check (low memory optimization). */
55020
55021#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
55022 extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
55023#else
55024 extdata = (const duk_uint8_t *) NULL;
55025#endif
55026
55027 /* Allocate and initialize string, not yet linked. This may cause a
55028 * GC which may cause other strings to be interned and inserted into
55029 * the string table before we insert our string. Finalizer execution
55030 * is disabled intentionally to avoid a finalizer from e.g. resizing
55031 * a buffer used as a data area for 'str'.
55032 */
55033
55034 res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata);
55035
55036 /* Allow side effects again: GC must be avoided until duk_hstring
55037 * result (if successful) has been INCREF'd.
55038 */
55039 DUK_ASSERT(heap->pf_prevent_count > 0);
55040 heap->pf_prevent_count--;
55041
55042 /* Alloc error handling. */
55043
55044 if (DUK_UNLIKELY(res == NULL)) {
55045#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
55046 if (extdata != NULL) {
55047 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata);
55048 }
55049#endif
55050 return NULL;
55051 }
55052
55053 /* Insert into string table. */
55054
55055#if defined(DUK_USE_STRTAB_PTRCOMP)
55056 slot = heap->strtable16 + (strhash & heap->st_mask);
55057#else
55058 slot = heap->strtable + (strhash & heap->st_mask);
55059#endif
55060 DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */
55061 res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot);
55062 *slot = DUK__HEAPPTR_ENC16(heap, res);
55063
55064 /* Update string count only for successful inserts. */
55065
55066#if defined(DUK__STRTAB_RESIZE_CHECK)
55067 heap->st_count++;
55068#endif
55069
55070 /* The duk_hstring is in the string table but is not yet strongly
55071 * reachable. Calling code MUST NOT make any allocations or other
55072 * side effects before the duk_hstring has been INCREF'd and made
55073 * reachable.
55074 */
55075
55076 return res;
55077}
55078
55079/*
55080 * Intern a string from str/blen, returning either an existing duk_hstring
55081 * or adding a new one into the string table. The input string does -not-
55082 * need to be NUL terminated.
55083 *
55084 * The input 'str' argument may point to a Duktape managed data area such as
55085 * the data area of a dynamic buffer. It's crucial to avoid any side effects
55086 * that might affect the data area (e.g. resize the dynamic buffer, or write
55087 * to the buffer) before the string is fully interned.
55088 */
55089
55090#if defined(DUK_USE_ROM_STRINGS)
55091DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) {
55092 duk_size_t lookup_hash;
55093 duk_hstring *curr;
55094
55095 DUK_ASSERT(heap != NULL);
55096 DUK_UNREF(heap);
55097
55098 lookup_hash = (blen << 4);
55099 if (blen > 0) {
55100 lookup_hash += str[0];
55101 }
55102 lookup_hash &= 0xff;
55103
55104 curr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]);
55105 while (curr != NULL) {
55106 /* Unsafe memcmp() because for zero blen, str may be NULL. */
55107 if (strhash == DUK_HSTRING_GET_HASH(curr) &&
55108 blen == DUK_HSTRING_GET_BYTELEN(curr) &&
55109 duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
55110 DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
55111 curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr)));
55112 return curr;
55113 }
55114 curr = curr->hdr.h_next;
55115 }
55116
55117 return NULL;
55118}
55119#endif /* DUK_USE_ROM_STRINGS */
55120
55121DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
55122 duk_uint32_t strhash;
55123 duk_hstring *h;
55124
55125 DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen));
55126
55127 /* Preliminaries. */
55128
55129 /* XXX: maybe just require 'str != NULL' even for zero size? */
55130 DUK_ASSERT(heap != NULL);
55131 DUK_ASSERT(blen == 0 || str != NULL);
55132 DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */
55133 strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
55134
55135 /* String table lookup. */
55136
55137 DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
55138 DUK_ASSERT(heap->st_size > 0);
55139 DUK_ASSERT(heap->st_size == heap->st_mask + 1);
55140#if defined(DUK_USE_STRTAB_PTRCOMP)
55141 h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]);
55142#else
55143 h = heap->strtable[strhash & heap->st_mask];
55144#endif
55145 while (h != NULL) {
55146 if (DUK_HSTRING_GET_HASH(h) == strhash &&
55147 DUK_HSTRING_GET_BYTELEN(h) == blen &&
55148 duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
55149 /* Found existing entry. */
55150 DUK_STATS_INC(heap, stats_strtab_intern_hit);
55151 return h;
55152 }
55153 h = h->hdr.h_next;
55154 }
55155
55156 /* ROM table lookup. Because this lookup is slower, do it only after
55157 * RAM lookup. This works because no ROM string is ever interned into
55158 * the RAM string table.
55159 */
55160
55161#if defined(DUK_USE_ROM_STRINGS)
55162 h = duk__strtab_romstring_lookup(heap, str, blen, strhash);
55163 if (h != NULL) {
55164 DUK_STATS_INC(heap, stats_strtab_intern_hit);
55165 return h;
55166 }
55167#endif
55168
55169 /* Not found in string table; insert. */
55170
55171 DUK_STATS_INC(heap, stats_strtab_intern_miss);
55172 h = duk__strtable_do_intern(heap, str, blen, strhash);
55173 return h; /* may be NULL */
55174}
55175
55176/*
55177 * Intern a string from u32.
55178 */
55179
55180/* XXX: Could arrange some special handling because we know that the result
55181 * will have an arridx flag and an ASCII flag, won't need a clen check, etc.
55182 */
55183
55184DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) {
55185 duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN];
55186 duk_uint8_t *p;
55187
55188 DUK_ASSERT(heap != NULL);
55189
55190 /* This is smaller and faster than a %lu sprintf. */
55191 p = buf + sizeof(buf);
55192 do {
55193 p--;
55194 *p = duk_lc_digits[val % 10];
55195 val = val / 10;
55196 } while (val != 0); /* For val == 0, emit exactly one '0'. */
55197 DUK_ASSERT(p >= buf);
55198
55199 return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p));
55200}
55201
55202/*
55203 * Checked convenience variants.
55204 *
55205 * XXX: Because the main use case is for the checked variants, make them the
55206 * main functionality and provide a safe variant separately (it is only needed
55207 * during heap init). The problem with that is that longjmp state and error
55208 * creation must already be possible to throw.
55209 */
55210
55211DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
55212 duk_hstring *res;
55213
55214 DUK_ASSERT(thr != NULL);
55215 DUK_ASSERT(thr->heap != NULL);
55216 DUK_ASSERT(blen == 0 || str != NULL);
55217
55218 res = duk_heap_strtable_intern(thr->heap, str, blen);
55219 if (DUK_UNLIKELY(res == NULL)) {
55220 DUK_ERROR_ALLOC_FAILED(thr);
55221 DUK_WO_NORETURN(return NULL;);
55222 }
55223 return res;
55224}
55225
55226#if defined(DUK_USE_LITCACHE_SIZE)
55227DUK_LOCAL duk_uint_t duk__strtable_litcache_key(const duk_uint8_t *str, duk_uint32_t blen) {
55228 duk_uintptr_t key;
55229
55230 DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
55231 DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
55232
55233 key = (duk_uintptr_t) blen ^ (duk_uintptr_t) str;
55234 key &= (duk_uintptr_t) (DUK_USE_LITCACHE_SIZE - 1); /* Assumes size is power of 2. */
55235 /* Due to masking, cast is in 32-bit range. */
55236 DUK_ASSERT(key <= DUK_UINT_MAX);
55237 return (duk_uint_t) key;
55238}
55239
55240DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
55241 duk_uint_t key;
55242 duk_litcache_entry *ent;
55243 duk_hstring *h;
55244
55245 /* Fast path check: literal exists in literal cache. */
55246 key = duk__strtable_litcache_key(str, blen);
55247 ent = thr->heap->litcache + key;
55248 if (ent->addr == str) {
55249 DUK_DD(DUK_DDPRINT("intern check for cached, pinned literal: str=%p, blen=%ld -> duk_hstring %!O",
55250 (const void *) str, (long) blen, (duk_heaphdr *) ent->h));
55251 DUK_ASSERT(ent->h != NULL);
55252 DUK_ASSERT(DUK_HSTRING_HAS_PINNED_LITERAL(ent->h));
55253 DUK_STATS_INC(thr->heap, stats_strtab_litcache_hit);
55254 return ent->h;
55255 }
55256
55257 /* Intern and update (overwrite) cache entry. */
55258 h = duk_heap_strtable_intern_checked(thr, str, blen);
55259 ent->addr = str;
55260 ent->h = h;
55261 DUK_STATS_INC(thr->heap, stats_strtab_litcache_miss);
55262
55263 /* Pin the duk_hstring until the next mark-and-sweep. This means
55264 * litcache entries don't need to be invalidated until the next
55265 * mark-and-sweep as their target duk_hstring is not freed before
55266 * the mark-and-sweep happens. The pin remains even if the literal
55267 * cache entry is overwritten, and is still useful to avoid string
55268 * table traffic.
55269 */
55270 if (!DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
55271 DUK_DD(DUK_DDPRINT("pin duk_hstring because it is a literal: %!O", (duk_heaphdr *) h));
55272 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
55273 DUK_HSTRING_INCREF(thr, h);
55274 DUK_HSTRING_SET_PINNED_LITERAL(h);
55275 DUK_STATS_INC(thr->heap, stats_strtab_litcache_pin);
55276 }
55277
55278 return h;
55279}
55280#endif /* DUK_USE_LITCACHE_SIZE */
55281
55282DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
55283 duk_hstring *res;
55284
55285 DUK_ASSERT(thr != NULL);
55286 DUK_ASSERT(thr->heap != NULL);
55287
55288 res = duk_heap_strtable_intern_u32(thr->heap, val);
55289 if (DUK_UNLIKELY(res == NULL)) {
55290 DUK_ERROR_ALLOC_FAILED(thr);
55291 DUK_WO_NORETURN(return NULL;);
55292 }
55293 return res;
55294}
55295
55296/*
55297 * Remove (unlink) a string from the string table.
55298 *
55299 * Just unlinks the duk_hstring, leaving link pointers as garbage.
55300 * Caller must free the string itself.
55301 */
55302
55303#if defined(DUK_USE_REFERENCE_COUNTING)
55304/* Unlink without a 'prev' pointer. */
55305DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) {
55306#if defined(DUK_USE_STRTAB_PTRCOMP)
55307 duk_uint16_t *slot;
55308#else
55309 duk_hstring **slot;
55310#endif
55311 duk_hstring *other;
55312 duk_hstring *prev;
55313
55314 DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx",
55315 (void *) heap, (void *) h,
55316 (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
55317 (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
55318
55319 DUK_ASSERT(heap != NULL);
55320 DUK_ASSERT(h != NULL);
55321
55322#if defined(DUK__STRTAB_RESIZE_CHECK)
55323 DUK_ASSERT(heap->st_count > 0);
55324 heap->st_count--;
55325#endif
55326
55327#if defined(DUK_USE_STRTAB_PTRCOMP)
55328 slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
55329#else
55330 slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
55331#endif
55332 other = DUK__HEAPPTR_DEC16(heap, *slot);
55333 DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */
55334
55335 prev = NULL;
55336 while (other != h) {
55337 prev = other;
55338 other = other->hdr.h_next;
55339 DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */
55340 }
55341 if (prev != NULL) {
55342 /* Middle of list. */
55343 prev->hdr.h_next = h->hdr.h_next;
55344 } else {
55345 /* Head of list. */
55346 *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
55347 }
55348
55349 /* There's no resize check on a string free. The next string
55350 * intern will do one.
55351 */
55352}
55353#endif /* DUK_USE_REFERENCE_COUNTING */
55354
55355/* Unlink with a 'prev' pointer. */
55356DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) {
55357#if defined(DUK_USE_STRTAB_PTRCOMP)
55358 duk_uint16_t *slot;
55359#else
55360 duk_hstring **slot;
55361#endif
55362
55363 DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx",
55364 (void *) heap, (void *) prev, (void *) h,
55365 (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
55366 (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
55367
55368 DUK_ASSERT(heap != NULL);
55369 DUK_ASSERT(h != NULL);
55370 DUK_ASSERT(prev == NULL || prev->hdr.h_next == h);
55371
55372#if defined(DUK__STRTAB_RESIZE_CHECK)
55373 DUK_ASSERT(heap->st_count > 0);
55374 heap->st_count--;
55375#endif
55376
55377 if (prev != NULL) {
55378 /* Middle of list. */
55379 prev->hdr.h_next = h->hdr.h_next;
55380 } else {
55381 /* Head of list. */
55382#if defined(DUK_USE_STRTAB_PTRCOMP)
55383 slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
55384#else
55385 slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
55386#endif
55387 DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h);
55388 *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
55389 }
55390}
55391
55392/*
55393 * Force string table resize check in mark-and-sweep.
55394 */
55395
55396DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) {
55397 /* Does only one grow/shrink step if needed. The heap->st_resizing
55398 * flag protects against recursive resizing.
55399 */
55400
55401 DUK_ASSERT(heap != NULL);
55402 DUK_UNREF(heap);
55403
55404#if defined(DUK__STRTAB_RESIZE_CHECK)
55405#if defined(DUK_USE_STRTAB_PTRCOMP)
55406 if (heap->strtable16 != NULL) {
55407#else
55408 if (heap->strtable != NULL) {
55409#endif
55410 duk__strtable_resize_check(heap);
55411 }
55412#endif
55413}
55414
55415/*
55416 * Free strings in the string table and the string table itself.
55417 */
55418
55419DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) {
55420#if defined(DUK_USE_STRTAB_PTRCOMP)
55421 duk_uint16_t *strtable;
55422 duk_uint16_t *st;
55423#else
55424 duk_hstring **strtable;
55425 duk_hstring **st;
55426#endif
55427 duk_hstring *h;
55428
55429 DUK_ASSERT(heap != NULL);
55430
55431#if defined(DUK_USE_ASSERTIONS)
55432 duk__strtable_assert_checks(heap);
55433#endif
55434
55435 /* Strtable can be NULL if heap init fails. However, in that case
55436 * heap->st_size is 0, so strtable == strtable_end and we skip the
55437 * loop without a special check.
55438 */
55439 strtable = DUK__GET_STRTABLE(heap);
55440 st = strtable + heap->st_size;
55441 DUK_ASSERT(strtable != NULL || heap->st_size == 0);
55442
55443 while (strtable != st) {
55444 --st;
55445 h = DUK__HEAPPTR_DEC16(heap, *st);
55446 while (h) {
55447 duk_hstring *h_next;
55448 h_next = h->hdr.h_next;
55449
55450 /* Strings may have inner refs (extdata) in some cases. */
55451 duk_free_hstring(heap, h);
55452
55453 h = h_next;
55454 }
55455 }
55456
55457 DUK_FREE(heap, strtable);
55458}
55459
55460/* automatic undefs */
55461#undef DUK__GET_STRTABLE
55462#undef DUK__HEAPPTR_DEC16
55463#undef DUK__HEAPPTR_ENC16
55464#undef DUK__STRTAB_U32_MAX_STRLEN
55465#line 1 "duk_heaphdr_assert.c"
55466/*
55467 * duk_heaphdr assertion helpers
55468 */
55469
55470/* #include duk_internal.h -> already included */
55471
55472#if defined(DUK_USE_ASSERTIONS)
55473
55474#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
55475DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) {
55476 DUK_UNREF(heap);
55477 if (h != NULL) {
55478 duk_heaphdr *h_prev, *h_next;
55479 h_prev = DUK_HEAPHDR_GET_PREV(heap, h);
55480 h_next = DUK_HEAPHDR_GET_NEXT(heap, h);
55481 DUK_ASSERT(h_prev == NULL || (DUK_HEAPHDR_GET_NEXT(heap, h_prev) == h));
55482 DUK_ASSERT(h_next == NULL || (DUK_HEAPHDR_GET_PREV(heap, h_next) == h));
55483 }
55484}
55485#else
55486DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) {
55487 DUK_UNREF(heap);
55488 DUK_UNREF(h);
55489}
55490#endif
55491
55492DUK_INTERNAL void duk_heaphdr_assert_valid(duk_heaphdr *h) {
55493 DUK_ASSERT(h != NULL);
55494 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
55495}
55496
55497/* Assert validity of a heaphdr, including all subclasses. */
55498DUK_INTERNAL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h) {
55499 switch (DUK_HEAPHDR_GET_TYPE(h)) {
55500 case DUK_HTYPE_OBJECT: {
55501 duk_hobject *h_obj = (duk_hobject *) h;
55502 DUK_HOBJECT_ASSERT_VALID(h_obj);
55503 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
55504 DUK_HCOMPFUNC_ASSERT_VALID((duk_hcompfunc *) h_obj);
55505 } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
55506 DUK_HNATFUNC_ASSERT_VALID((duk_hnatfunc *) h_obj);
55507 } else if (DUK_HOBJECT_IS_DECENV(h_obj)) {
55508 DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) h_obj);
55509 } else if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
55510 DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_obj);
55511 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
55512#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
55513 DUK_HBUFOBJ_ASSERT_VALID((duk_hbufobj *) h_obj);
55514#endif
55515 } else if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
55516 DUK_HBOUNDFUNC_ASSERT_VALID((duk_hboundfunc *) h_obj);
55517 } else if (DUK_HOBJECT_IS_PROXY(h_obj)) {
55518 DUK_HPROXY_ASSERT_VALID((duk_hproxy *) h_obj);
55519 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
55520 DUK_HTHREAD_ASSERT_VALID((duk_hthread *) h_obj);
55521 } else {
55522 /* Just a plain object. */
55523 ;
55524 }
55525 break;
55526 }
55527 case DUK_HTYPE_STRING: {
55528 duk_hstring *h_str = (duk_hstring *) h;
55529 DUK_HSTRING_ASSERT_VALID(h_str);
55530 break;
55531 }
55532 case DUK_HTYPE_BUFFER: {
55533 duk_hbuffer *h_buf = (duk_hbuffer *) h;
55534 DUK_HBUFFER_ASSERT_VALID(h_buf);
55535 break;
55536 }
55537 default: {
55538 DUK_ASSERT(0);
55539 }
55540 }
55541}
55542
55543#endif /* DUK_USE_ASSERTIONS */
55544#line 1 "duk_hobject_alloc.c"
55545/*
55546 * Hobject allocation.
55547 *
55548 * Provides primitive allocation functions for all object types (plain object,
55549 * compiled function, native function, thread). The object return is not yet
55550 * in "heap allocated" list and has a refcount of zero, so caller must careful.
55551 */
55552
55553/* XXX: In most cases there's no need for plain allocation without pushing
55554 * to the value stack. Maybe rework contract?
55555 */
55556
55557/* #include duk_internal.h -> already included */
55558
55559/*
55560 * Helpers.
55561 */
55562
55563DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) {
55564 DUK_ASSERT(obj != NULL);
55565 /* Zeroed by caller. */
55566
55567 obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT;
55568 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT); /* Assume zero shift. */
55569
55570#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55571 DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL);
55572 DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
55573#endif
55574#if defined(DUK_USE_HEAPPTR16)
55575 /* Zero encoded pointer is required to match NULL. */
55576 DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
55577#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
55578 DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
55579#endif
55580#endif
55581 DUK_HEAPHDR_ASSERT_LINKS(heap, &obj->hdr);
55582 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
55583
55584 /* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
55585 * with this properly. This is intentional: empty objects consume a minimum
55586 * amount of memory. Further, an initial allocation might fail and cause
55587 * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
55588 */
55589}
55590
55591DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) {
55592 void *res;
55593
55594 res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size);
55595 DUK_ASSERT(res != NULL);
55596 duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res);
55597 return res;
55598}
55599
55600/*
55601 * Allocate an duk_hobject.
55602 *
55603 * The allocated object has no allocation for properties; the caller may
55604 * want to force a resize if a desired size is known.
55605 *
55606 * The allocated object has zero reference count and is not reachable.
55607 * The caller MUST make the object reachable and increase its reference
55608 * count before invoking any operation that might require memory allocation.
55609 */
55610
55611DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
55612 duk_hobject *res;
55613
55614 DUK_ASSERT(heap != NULL);
55615
55616 /* different memory layout, alloc size, and init */
55617 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
55618 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
55619 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0);
55620
55621 res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject));
55622 if (DUK_UNLIKELY(res == NULL)) {
55623 return NULL;
55624 }
55625 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
55626
55627 duk__init_object_parts(heap, hobject_flags, res);
55628
55629 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
55630 return res;
55631}
55632
55633DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55634 duk_hobject *res;
55635
55636 res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject));
55637 return res;
55638}
55639
55640DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55641 duk_hcompfunc *res;
55642
55643 res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc));
55644#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55645#if defined(DUK_USE_HEAPPTR16)
55646 /* NULL pointer is required to encode to zero, so memset is enough. */
55647#else
55648 res->data = NULL;
55649 res->funcs = NULL;
55650 res->bytecode = NULL;
55651#endif
55652 res->lex_env = NULL;
55653 res->var_env = NULL;
55654#endif
55655
55656 return res;
55657}
55658
55659DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55660 duk_hnatfunc *res;
55661
55662 res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc));
55663#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55664 res->func = NULL;
55665#endif
55666
55667 return res;
55668}
55669
55670DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
55671 duk_hboundfunc *res;
55672
55673 res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc));
55674 if (!res) {
55675 return NULL;
55676 }
55677 duk_memzero(res, sizeof(duk_hboundfunc));
55678
55679 duk__init_object_parts(heap, hobject_flags, &res->obj);
55680
55681 DUK_TVAL_SET_UNDEFINED(&res->target);
55682 DUK_TVAL_SET_UNDEFINED(&res->this_binding);
55683
55684#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55685 res->args = NULL;
55686#endif
55687
55688 return res;
55689}
55690
55691#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
55692DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55693 duk_hbufobj *res;
55694
55695 res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj));
55696#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55697 res->buf = NULL;
55698 res->buf_prop = NULL;
55699#endif
55700
55701 DUK_HBUFOBJ_ASSERT_VALID(res);
55702 return res;
55703}
55704#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
55705
55706/* Allocate a new thread.
55707 *
55708 * Leaves the built-ins array uninitialized. The caller must either
55709 * initialize a new global context or share existing built-ins from
55710 * another thread.
55711 */
55712DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
55713 duk_hthread *res;
55714
55715 res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
55716 if (DUK_UNLIKELY(res == NULL)) {
55717 return NULL;
55718 }
55719 duk_memzero(res, sizeof(duk_hthread));
55720
55721 duk__init_object_parts(heap, hobject_flags, &res->obj);
55722
55723#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55724 res->ptr_curr_pc = NULL;
55725 res->heap = NULL;
55726 res->valstack = NULL;
55727 res->valstack_end = NULL;
55728 res->valstack_alloc_end = NULL;
55729 res->valstack_bottom = NULL;
55730 res->valstack_top = NULL;
55731 res->callstack_curr = NULL;
55732 res->resumer = NULL;
55733 res->compile_ctx = NULL,
55734#if defined(DUK_USE_HEAPPTR16)
55735 res->strs16 = NULL;
55736#else
55737 res->strs = NULL;
55738#endif
55739 {
55740 duk_small_uint_t i;
55741 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
55742 res->builtins[i] = NULL;
55743 }
55744 }
55745#endif
55746 /* When nothing is running, API calls are in non-strict mode. */
55747 DUK_ASSERT(res->strict == 0);
55748
55749 res->heap = heap;
55750
55751 /* XXX: Any reason not to merge duk_hthread_alloc.c here? */
55752 return res;
55753}
55754
55755DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55756 duk_hthread *res;
55757
55758 res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags);
55759 if (res == NULL) {
55760 DUK_ERROR_ALLOC_FAILED(thr);
55761 DUK_WO_NORETURN(return NULL;);
55762 }
55763 return res;
55764}
55765
55766DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55767 duk_harray *res;
55768
55769 res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray));
55770
55771 DUK_ASSERT(res->length == 0);
55772
55773 return res;
55774}
55775
55776DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55777 duk_hdecenv *res;
55778
55779 res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv));
55780#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55781 res->thread = NULL;
55782 res->varmap = NULL;
55783#endif
55784
55785 DUK_ASSERT(res->thread == NULL);
55786 DUK_ASSERT(res->varmap == NULL);
55787 DUK_ASSERT(res->regbase_byteoff == 0);
55788
55789 return res;
55790}
55791
55792DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55793 duk_hobjenv *res;
55794
55795 res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv));
55796#if defined(DUK_USE_EXPLICIT_NULL_INIT)
55797 res->target = NULL;
55798#endif
55799
55800 DUK_ASSERT(res->target == NULL);
55801
55802 return res;
55803}
55804
55805DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
55806 duk_hproxy *res;
55807
55808 res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy));
55809
55810 /* Leave ->target and ->handler uninitialized, as caller will always
55811 * explicitly initialize them before any side effects are possible.
55812 */
55813
55814 return res;
55815}
55816#line 1 "duk_hobject_assert.c"
55817/*
55818 * duk_hobject and subclass assertion helpers
55819 */
55820
55821/* #include duk_internal.h -> already included */
55822
55823#if defined(DUK_USE_ASSERTIONS)
55824
55825DUK_INTERNAL void duk_hobject_assert_valid(duk_hobject *h) {
55826 DUK_ASSERT(h != NULL);
55827 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h) ||
55828 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FUNCTION);
55829 DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ(h) ||
55830 (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER ||
55831 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_DATAVIEW ||
55832 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT8ARRAY ||
55833 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8ARRAY ||
55834 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY ||
55835 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT16ARRAY ||
55836 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT16ARRAY ||
55837 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT32ARRAY ||
55838 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT32ARRAY ||
55839 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT32ARRAY ||
55840 DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT64ARRAY));
55841 /* Object is an Array <=> object has exotic array behavior */
55842 DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) ||
55843 (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)));
55844}
55845
55846DUK_INTERNAL void duk_harray_assert_valid(duk_harray *h) {
55847 DUK_ASSERT(h != NULL);
55848 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
55849 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) h));
55850}
55851
55852DUK_INTERNAL void duk_hboundfunc_assert_valid(duk_hboundfunc *h) {
55853 DUK_ASSERT(h != NULL);
55854 DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) h));
55855 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h->target) ||
55856 (DUK_TVAL_IS_OBJECT(&h->target) &&
55857 DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h->target))));
55858 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&h->this_binding));
55859 DUK_ASSERT(h->nargs == 0 || h->args != NULL);
55860}
55861
55862#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
55863DUK_INTERNAL void duk_hbufobj_assert_valid(duk_hbufobj *h) {
55864 DUK_ASSERT(h != NULL);
55865 DUK_ASSERT(h->shift <= 3);
55866 DUK_ASSERT(h->elem_type <= DUK_HBUFOBJ_ELEM_MAX);
55867 DUK_ASSERT((h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8) ||
55868 (h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) ||
55869 (h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_INT8) ||
55870 (h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT16) ||
55871 (h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_INT16) ||
55872 (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT32) ||
55873 (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_INT32) ||
55874 (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) ||
55875 (h->shift == 3 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64));
55876 DUK_ASSERT(h->is_typedarray == 0 || h->is_typedarray == 1);
55877 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h));
55878 if (h->buf == NULL) {
55879 DUK_ASSERT(h->offset == 0);
55880 DUK_ASSERT(h->length == 0);
55881 } else {
55882 /* No assertions for offset or length; in particular,
55883 * it's OK for length to be longer than underlying
55884 * buffer. Just ensure they don't wrap when added.
55885 */
55886 DUK_ASSERT(h->offset + h->length >= h->offset);
55887 }
55888}
55889#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
55890
55891DUK_INTERNAL void duk_hcompfunc_assert_valid(duk_hcompfunc *h) {
55892 DUK_ASSERT(h != NULL);
55893}
55894
55895DUK_INTERNAL void duk_hnatfunc_assert_valid(duk_hnatfunc *h) {
55896 DUK_ASSERT(h != NULL);
55897}
55898
55899DUK_INTERNAL void duk_hdecenv_assert_valid(duk_hdecenv *h) {
55900 DUK_ASSERT(h != NULL);
55901 DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) h));
55902 DUK_ASSERT(h->thread == NULL || h->varmap != NULL);
55903}
55904
55905DUK_INTERNAL void duk_hobjenv_assert_valid(duk_hobjenv *h) {
55906 DUK_ASSERT(h != NULL);
55907 DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) h));
55908 DUK_ASSERT(h->target != NULL);
55909 DUK_ASSERT(h->has_this == 0 || h->has_this == 1);
55910}
55911
55912DUK_INTERNAL void duk_hproxy_assert_valid(duk_hproxy *h) {
55913 DUK_ASSERT(h != NULL);
55914 DUK_ASSERT(h->target != NULL);
55915 DUK_ASSERT(h->handler != NULL);
55916 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) h));
55917}
55918
55919DUK_INTERNAL void duk_hthread_assert_valid(duk_hthread *thr) {
55920 DUK_ASSERT(thr != NULL);
55921 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) thr) == DUK_HTYPE_OBJECT);
55922 DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) thr));
55923 DUK_ASSERT(thr->unused1 == 0);
55924 DUK_ASSERT(thr->unused2 == 0);
55925}
55926
55927DUK_INTERNAL void duk_ctx_assert_valid(duk_hthread *thr) {
55928 DUK_ASSERT(thr != NULL);
55929 DUK_HTHREAD_ASSERT_VALID(thr);
55930 DUK_ASSERT(thr->valstack != NULL);
55931 DUK_ASSERT(thr->valstack_bottom != NULL);
55932 DUK_ASSERT(thr->valstack_top != NULL);
55933 DUK_ASSERT(thr->valstack_end != NULL);
55934 DUK_ASSERT(thr->valstack_alloc_end != NULL);
55935 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack);
55936 DUK_ASSERT(thr->valstack_end >= thr->valstack);
55937 DUK_ASSERT(thr->valstack_top >= thr->valstack);
55938 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
55939 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
55940 DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
55941}
55942
55943#endif /* DUK_USE_ASSERTIONS */
55944#line 1 "duk_hobject_enum.c"
55945/*
55946 * Object enumeration support.
55947 *
55948 * Creates an internal enumeration state object to be used e.g. with for-in
55949 * enumeration. The state object contains a snapshot of target object keys
55950 * and internal control state for enumeration. Enumerator flags allow caller
55951 * to e.g. request internal/non-enumerable properties, and to enumerate only
55952 * "own" properties.
55953 *
55954 * Also creates the result value for e.g. Object.keys() based on the same
55955 * internal structure.
55956 *
55957 * This snapshot-based enumeration approach is used to simplify enumeration:
55958 * non-snapshot-based approaches are difficult to reconcile with mutating
55959 * the enumeration target, running multiple long-lived enumerators at the
55960 * same time, garbage collection details, etc. The downside is that the
55961 * enumerator object is memory inefficient especially for iterating arrays.
55962 */
55963
55964/* #include duk_internal.h -> already included */
55965
55966/* XXX: identify enumeration target with an object index (not top of stack) */
55967
55968/* First enumerated key index in enumerator object, must match exactly the
55969 * number of control properties inserted to the enumerator.
55970 */
55971#define DUK__ENUM_START_INDEX 2
55972
55973/* Current implementation suffices for ES2015 for now because there's no symbol
55974 * sorting, so commented out for now.
55975 */
55976
55977/*
55978 * Helper to sort enumeration keys using a callback for pairwise duk_hstring
55979 * comparisons. The keys are in the enumeration object entry part, starting
55980 * from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values
55981 * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true,
55982 * so it suffices to just switch keys without switching values.
55983 *
55984 * ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
55985 * (1) array indices in ascending order,
55986 * (2) non-array-index keys in insertion order, and
55987 * (3) symbols in insertion order.
55988 * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
55989 *
55990 * This rule is applied to "own properties" at each inheritance level;
55991 * non-duplicate parent keys always follow child keys. For example,
55992 * an inherited array index will enumerate -after- a symbol in the
55993 * child.
55994 *
55995 * Insertion sort is used because (1) it's simple and compact, (2) works
55996 * in-place, (3) minimizes operations if data is already nearly sorted,
55997 * (4) doesn't reorder elements considered equal.
55998 * http://en.wikipedia.org/wiki/Insertion_sort
55999 */
56000
56001/* Sort key, must hold array indices, "not array index" marker, and one more
56002 * higher value for symbols.
56003 */
56004#if !defined(DUK_USE_SYMBOL_BUILTIN)
56005typedef duk_uint32_t duk__sort_key_t;
56006#elif defined(DUK_USE_64BIT_OPS)
56007typedef duk_uint64_t duk__sort_key_t;
56008#else
56009typedef duk_double_t duk__sort_key_t;
56010#endif
56011
56012/* Get sort key for a duk_hstring. */
56013DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) {
56014 duk__sort_key_t val;
56015
56016 /* For array indices [0,0xfffffffe] use the array index as is.
56017 * For strings, use 0xffffffff, the marker 'arridx' already in
56018 * duk_hstring. For symbols, any value above 0xffffffff works,
56019 * as long as it is the same for all symbols; currently just add
56020 * the masked flag field into the arridx temporary.
56021 */
56022 DUK_ASSERT(x != NULL);
56023 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX);
56024
56025 val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x);
56026
56027#if defined(DUK_USE_SYMBOL_BUILTIN)
56028 val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL);
56029#endif
56030
56031 return (duk__sort_key_t) val;
56032}
56033
56034/* Insert element 'b' after element 'a'? */
56035DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) {
56036 duk__sort_key_t val_a;
56037
56038 DUK_ASSERT(a != NULL);
56039 DUK_ASSERT(b != NULL);
56040 DUK_UNREF(b); /* Not actually needed now, val_b suffices. */
56041
56042 val_a = duk__hstring_sort_key(a);
56043
56044 if (val_a > val_b) {
56045 return 0;
56046 } else {
56047 return 1;
56048 }
56049}
56050
56051DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk_int_fast32_t idx_start, duk_int_fast32_t idx_end) {
56052 duk_hstring **keys;
56053 duk_int_fast32_t idx;
56054
56055 DUK_ASSERT(h_obj != NULL);
56056 DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
56057 DUK_ASSERT(idx_end >= idx_start);
56058 DUK_UNREF(thr);
56059
56060 if (idx_end <= idx_start + 1) {
56061 return; /* Zero or one element(s). */
56062 }
56063
56064 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
56065
56066 for (idx = idx_start + 1; idx < idx_end; idx++) {
56067 duk_hstring *h_curr;
56068 duk_int_fast32_t idx_insert;
56069 duk__sort_key_t val_curr;
56070
56071 h_curr = keys[idx];
56072 DUK_ASSERT(h_curr != NULL);
56073
56074 /* Scan backwards for insertion place. This works very well
56075 * when the elements are nearly in order which is the common
56076 * (and optimized for) case.
56077 */
56078
56079 val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */
56080 for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
56081 duk_hstring *h_insert;
56082 h_insert = keys[idx_insert];
56083 DUK_ASSERT(h_insert != NULL);
56084
56085 if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
56086 break;
56087 }
56088 }
56089 /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++
56090 * brings us back to idx_start.
56091 */
56092 idx_insert++;
56093 DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx);
56094
56095 /* .-- p_insert .-- p_curr
56096 * v v
56097 * | ... | insert | ... | curr
56098 */
56099
56100 /* This could also done when the keys are in order, i.e.
56101 * idx_insert == idx. The result would be an unnecessary
56102 * memmove() but we use an explicit check because the keys
56103 * are very often in order already.
56104 */
56105 if (idx != idx_insert) {
56106 duk_memmove((void *) (keys + idx_insert + 1),
56107 (const void *) (keys + idx_insert),
56108 ((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
56109 keys[idx_insert] = h_curr;
56110 }
56111 }
56112
56113 /* Entry part has been reordered now with no side effects.
56114 * If the object has a hash part, it will now be incorrect
56115 * and we need to rehash. Do that by forcing a resize to
56116 * the current size.
56117 */
56118 duk_hobject_resize_entrypart(thr, h_obj, DUK_HOBJECT_GET_ESIZE(h_obj));
56119}
56120
56121/*
56122 * Create an internal enumerator object E, which has its keys ordered
56123 * to match desired enumeration ordering. Also initialize internal control
56124 * properties for enumeration.
56125 *
56126 * Note: if an array was used to hold enumeration keys instead, an array
56127 * scan would be needed to eliminate duplicates found in the prototype chain.
56128 */
56129
56130DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) {
56131 /* 'k' may be unreachable on entry so must push without any
56132 * potential for GC.
56133 */
56134 duk_push_hstring(thr, k);
56135 duk_push_true(thr);
56136 duk_put_prop(thr, -3);
56137}
56138
56139DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
56140 duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
56141}
56142
56143DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) {
56144 duk_hobject *enum_target;
56145 duk_hobject *curr;
56146 duk_hobject *res;
56147#if defined(DUK_USE_ES6_PROXY)
56148 duk_hobject *h_proxy_target;
56149 duk_hobject *h_proxy_handler;
56150 duk_hobject *h_trap_result;
56151#endif
56152 duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
56153 duk_uint_fast32_t sort_start_index;
56154
56155 DUK_ASSERT(thr != NULL);
56156
56157 enum_target = duk_require_hobject(thr, -1);
56158 DUK_ASSERT(enum_target != NULL);
56159
56160 duk_push_bare_object(thr);
56161 res = duk_known_hobject(thr, -1);
56162
56163 /* [enum_target res] */
56164
56165 /* Target must be stored so that we can recheck whether or not
56166 * keys still exist when we enumerate. This is not done if the
56167 * enumeration result comes from a proxy trap as there is no
56168 * real object to check against.
56169 */
56170 duk_push_hobject(thr, enum_target);
56171 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */
56172
56173 /* Initialize index so that we skip internal control keys. */
56174 duk_push_int(thr, DUK__ENUM_START_INDEX);
56175 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); /* Target is bare, plain put OK. */
56176
56177 /*
56178 * Proxy object handling
56179 */
56180
56181#if defined(DUK_USE_ES6_PROXY)
56182 if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
56183 goto skip_proxy;
56184 }
56185 if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target,
56186 &h_proxy_target,
56187 &h_proxy_handler))) {
56188 goto skip_proxy;
56189 }
56190
56191 /* XXX: share code with Object.keys() Proxy handling */
56192
56193 /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate"
56194 * has been obsoleted and "ownKeys" is used instead.
56195 */
56196 DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
56197 duk_push_hobject(thr, h_proxy_handler);
56198 if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
56199 /* No need to replace the 'enum_target' value in stack, only the
56200 * enum_target reference. This also ensures that the original
56201 * enum target is reachable, which keeps the proxy and the proxy
56202 * target reachable. We do need to replace the internal _Target.
56203 */
56204 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead"));
56205 DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
56206 enum_target = h_proxy_target;
56207
56208 duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */
56209 duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */
56210
56211 duk_pop_2(thr); /* -> [ ... enum_target res ] */
56212 goto skip_proxy;
56213 }
56214
56215 /* [ ... enum_target res handler trap ] */
56216 duk_insert(thr, -2);
56217 duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
56218 duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
56219 h_trap_result = duk_require_hobject(thr, -1);
56220 DUK_UNREF(h_trap_result);
56221
56222 duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
56223 /* -> [ ... enum_target res trap_result keys_array ] */
56224
56225 /* Copy cleaned up trap result keys into the enumerator object. */
56226 /* XXX: result is a dense array; could make use of that. */
56227 DUK_ASSERT(duk_is_array(thr, -1));
56228 len = (duk_uint_fast32_t) duk_get_length(thr, -1);
56229 for (i = 0; i < len; i++) {
56230 (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i);
56231 DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */
56232 /* [ ... enum_target res trap_result keys_array val ] */
56233 duk_push_true(thr);
56234 /* [ ... enum_target res trap_result keys_array val true ] */
56235 duk_put_prop(thr, -5);
56236 }
56237 /* [ ... enum_target res trap_result keys_array ] */
56238 duk_pop_2(thr);
56239 duk_remove_m2(thr);
56240
56241 /* [ ... res ] */
56242
56243 /* The internal _Target property is kept pointing to the original
56244 * enumeration target (the proxy object), so that the enumerator
56245 * 'next' operation can read property values if so requested. The
56246 * fact that the _Target is a proxy disables key existence check
56247 * during enumeration.
56248 */
56249 DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
56250 goto compact_and_return;
56251
56252 skip_proxy:
56253#endif /* DUK_USE_ES6_PROXY */
56254
56255 curr = enum_target;
56256 sort_start_index = DUK__ENUM_START_INDEX;
56257 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX);
56258 while (curr) {
56259 duk_uint_fast32_t sort_end_index;
56260#if !defined(DUK_USE_PREFER_SIZE)
56261 duk_bool_t need_sort = 0;
56262#endif
56263 duk_bool_t cond;
56264
56265 /* Enumeration proceeds by inheritance level. Virtual
56266 * properties need to be handled specially, followed by
56267 * array part, and finally entry part.
56268 *
56269 * If there are array index keys in the entry part or any
56270 * other risk of the ES2015 [[OwnPropertyKeys]] order being
56271 * violated, need_sort is set and an explicit ES2015 sort is
56272 * done for the inheritance level.
56273 */
56274
56275 /* XXX: inheriting from proxy */
56276
56277 /*
56278 * Virtual properties.
56279 *
56280 * String and buffer indices are virtual and always enumerable,
56281 * 'length' is virtual and non-enumerable. Array and arguments
56282 * object props have special behavior but are concrete.
56283 *
56284 * String and buffer objects don't have an array part so as long
56285 * as virtual array index keys are enumerated first, we don't
56286 * need to set need_sort.
56287 */
56288
56289#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56290 cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr);
56291#else
56292 cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr);
56293#endif
56294 cond = cond && !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS);
56295 if (cond) {
56296 duk_bool_t have_length = 1;
56297
56298 /* String and buffer enumeration behavior is identical now,
56299 * so use shared handler.
56300 */
56301 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
56302 duk_hstring *h_val;
56303 h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
56304 DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
56305 len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
56306 }
56307#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56308 else {
56309 duk_hbufobj *h_bufobj;
56310 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr));
56311 h_bufobj = (duk_hbufobj *) curr;
56312
56313 if (h_bufobj == NULL || !h_bufobj->is_typedarray) {
56314 /* Zero length seems like a good behavior for neutered buffers.
56315 * ArrayBuffer (non-view) and DataView don't have index properties
56316 * or .length property.
56317 */
56318 len = 0;
56319 have_length = 0;
56320 } else {
56321 /* There's intentionally no check for
56322 * current underlying buffer length.
56323 */
56324 len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
56325 }
56326 }
56327#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
56328
56329 for (i = 0; i < len; i++) {
56330 duk_hstring *k;
56331
56332 /* This is a bit fragile: the string is not
56333 * reachable until it is pushed by the helper.
56334 */
56335 k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);
56336 DUK_ASSERT(k);
56337
56338 duk__add_enum_key(thr, k);
56339
56340 /* [enum_target res] */
56341 }
56342
56343 /* 'length' and other virtual properties are not
56344 * enumerable, but are included if non-enumerable
56345 * properties are requested.
56346 */
56347
56348 if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
56349 duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
56350 }
56351 }
56352
56353 /*
56354 * Array part
56355 */
56356
56357 cond = !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS);
56358 if (cond) {
56359 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
56360 duk_hstring *k;
56361 duk_tval *tv;
56362
56363 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
56364 if (DUK_TVAL_IS_UNUSED(tv)) {
56365 continue;
56366 }
56367 k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */
56368 DUK_ASSERT(k);
56369
56370 duk__add_enum_key(thr, k);
56371
56372 /* [enum_target res] */
56373 }
56374
56375 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
56376 /* Array .length comes after numeric indices. */
56377 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
56378 duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
56379 }
56380 }
56381 }
56382
56383 /*
56384 * Entries part
56385 */
56386
56387 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
56388 duk_hstring *k;
56389
56390 k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
56391 if (!k) {
56392 continue;
56393 }
56394 if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) &&
56395 !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) {
56396 continue;
56397 }
56398 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
56399 if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) &&
56400 DUK_HSTRING_HAS_HIDDEN(k)) {
56401 continue;
56402 }
56403 if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
56404 continue;
56405 }
56406#if !defined(DUK_USE_PREFER_SIZE)
56407 need_sort = 1;
56408#endif
56409 } else {
56410 DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */
56411 if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
56412 continue;
56413 }
56414 }
56415 if (DUK_HSTRING_HAS_ARRIDX(k)) {
56416 /* This in currently only possible if the
56417 * object has no array part: the array part
56418 * is exhaustive when it is present.
56419 */
56420#if !defined(DUK_USE_PREFER_SIZE)
56421 need_sort = 1;
56422#endif
56423 } else {
56424 if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) {
56425 continue;
56426 }
56427 }
56428
56429 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
56430 !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
56431
56432 duk__add_enum_key(thr, k);
56433
56434 /* [enum_target res] */
56435 }
56436
56437 /* Sort enumerated keys according to ES2015 requirements for
56438 * the "inheritance level" just processed. This is far from
56439 * optimal, ES2015 semantics could be achieved more efficiently
56440 * by handling array index string keys (and symbol keys)
56441 * specially above in effect doing the sort inline.
56442 *
56443 * Skip the sort if array index sorting is requested because
56444 * we must consider all keys, also inherited, so an explicit
56445 * sort is done for the whole result after we're done with the
56446 * prototype chain.
56447 *
56448 * Also skip the sort if need_sort == 0, i.e. we know for
56449 * certain that the enumerated order is already correct.
56450 */
56451 sort_end_index = DUK_HOBJECT_GET_ENEXT(res);
56452
56453 if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
56454#if defined(DUK_USE_PREFER_SIZE)
56455 duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
56456#else
56457 if (need_sort) {
56458 DUK_DDD(DUK_DDDPRINT("need to sort"));
56459 duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
56460 } else {
56461 DUK_DDD(DUK_DDDPRINT("no need to sort"));
56462 }
56463#endif
56464 }
56465
56466 sort_start_index = sort_end_index;
56467
56468 if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
56469 break;
56470 }
56471
56472 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
56473 }
56474
56475 /* [enum_target res] */
56476
56477 duk_remove_m2(thr);
56478
56479 /* [res] */
56480
56481 if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) {
56482 /* Some E5/E5.1 algorithms require that array indices are iterated
56483 * in a strictly ascending order. This is the case for e.g.
56484 * Array.prototype.forEach() and JSON.stringify() PropertyList
56485 * handling. The caller can request an explicit sort in these
56486 * cases.
56487 */
56488
56489 /* Sort to ES2015 order which works for pure array incides but
56490 * also for mixed keys.
56491 */
56492 duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res));
56493 }
56494
56495#if defined(DUK_USE_ES6_PROXY)
56496 compact_and_return:
56497#endif
56498 /* compact; no need to seal because object is internal */
56499 duk_hobject_compact_props(thr, res);
56500
56501 DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
56502}
56503
56504/*
56505 * Returns non-zero if a key and/or value was enumerated, and:
56506 *
56507 * [enum] -> [key] (get_value == 0)
56508 * [enum] -> [key value] (get_value == 1)
56509 *
56510 * Returns zero without pushing anything on the stack otherwise.
56511 */
56512DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) {
56513 duk_hobject *e;
56514 duk_hobject *enum_target;
56515 duk_hstring *res = NULL;
56516 duk_uint_fast32_t idx;
56517 duk_bool_t check_existence;
56518
56519 DUK_ASSERT(thr != NULL);
56520
56521 /* [... enum] */
56522
56523 e = duk_require_hobject(thr, -1);
56524
56525 /* XXX use get tval ptr, more efficient */
56526 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT);
56527 idx = (duk_uint_fast32_t) duk_require_uint(thr, -1);
56528 duk_pop(thr);
56529 DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
56530
56531 /* Enumeration keys are checked against the enumeration target (to see
56532 * that they still exist). In the proxy enumeration case _Target will
56533 * be the proxy, and checking key existence against the proxy is not
56534 * required (or sensible, as the keys may be fully virtual).
56535 */
56536 duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET);
56537 enum_target = duk_require_hobject(thr, -1);
56538 DUK_ASSERT(enum_target != NULL);
56539#if defined(DUK_USE_ES6_PROXY)
56540 check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target));
56541#else
56542 check_existence = 1;
56543#endif
56544 duk_pop(thr); /* still reachable */
56545
56546 DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
56547 (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1)));
56548
56549 /* no array part */
56550 for (;;) {
56551 duk_hstring *k;
56552
56553 if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
56554 DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
56555 break;
56556 }
56557
56558 /* we know these because enum objects are internally created */
56559 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
56560 DUK_ASSERT(k != NULL);
56561 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
56562 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
56563
56564 idx++;
56565
56566 /* recheck that the property still exists */
56567 if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
56568 DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
56569 continue;
56570 }
56571
56572 DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
56573 res = k;
56574 break;
56575 }
56576
56577 DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
56578
56579 duk_push_u32(thr, (duk_uint32_t) idx);
56580 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
56581
56582 /* [... enum] */
56583
56584 if (res) {
56585 duk_push_hstring(thr, res);
56586 if (get_value) {
56587 duk_push_hobject(thr, enum_target);
56588 duk_dup_m2(thr); /* -> [... enum key enum_target key] */
56589 duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */
56590 duk_remove_m2(thr); /* -> [... enum key val] */
56591 duk_remove(thr, -3); /* -> [... key val] */
56592 } else {
56593 duk_remove_m2(thr); /* -> [... key] */
56594 }
56595 return 1;
56596 } else {
56597 duk_pop(thr); /* -> [...] */
56598 return 0;
56599 }
56600}
56601
56602/*
56603 * Get enumerated keys in an ECMAScript array. Matches Object.keys() behavior
56604 * described in E5 Section 15.2.3.14.
56605 */
56606
56607DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) {
56608 duk_hobject *e;
56609 duk_hstring **keys;
56610 duk_tval *tv;
56611 duk_uint_fast32_t count;
56612
56613 DUK_ASSERT(thr != NULL);
56614 DUK_ASSERT(duk_get_hobject(thr, -1) != NULL);
56615
56616 /* Create a temporary enumerator to get the (non-duplicated) key list;
56617 * the enumerator state is initialized without being needed, but that
56618 * has little impact.
56619 */
56620
56621 duk_hobject_enumerator_create(thr, enum_flags);
56622 e = duk_known_hobject(thr, -1);
56623
56624 /* [enum_target enum res] */
56625
56626 /* Create dense result array to exact size. */
56627 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
56628 count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
56629
56630 /* XXX: uninit would be OK */
56631 tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);
56632 DUK_ASSERT(count == 0 || tv != NULL);
56633 DUK_ASSERT(!duk_is_bare_object(thr, -1));
56634
56635 /* Fill result array, no side effects. */
56636
56637 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e);
56638 keys += DUK__ENUM_START_INDEX;
56639
56640 while (count-- > 0) {
56641 duk_hstring *k;
56642
56643 k = *keys++;
56644 DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */
56645
56646 DUK_TVAL_SET_STRING(tv, k);
56647 tv++;
56648 DUK_HSTRING_INCREF(thr, k);
56649 }
56650
56651 /* [enum_target enum res] */
56652 duk_remove_m2(thr);
56653
56654 /* [enum_target res] */
56655
56656 return 1; /* return 1 to allow callers to tail call */
56657}
56658
56659/* automatic undefs */
56660#undef DUK__ENUM_START_INDEX
56661#line 1 "duk_hobject_misc.c"
56662/*
56663 * Misc support functions
56664 */
56665
56666/* #include duk_internal.h -> already included */
56667
56668DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
56669 duk_uint_t sanity;
56670
56671 DUK_ASSERT(thr != NULL);
56672
56673 /* False if the object is NULL or the prototype 'p' is NULL.
56674 * In particular, false if both are NULL (don't compare equal).
56675 */
56676 if (h == NULL || p == NULL) {
56677 return 0;
56678 }
56679
56680 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
56681 do {
56682 if (h == p) {
56683 return 1;
56684 }
56685
56686 if (sanity-- == 0) {
56687 if (ignore_loop) {
56688 break;
56689 } else {
56690 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
56691 DUK_WO_NORETURN(return 0;);
56692 }
56693 }
56694 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
56695 } while (h);
56696
56697 return 0;
56698}
56699
56700DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
56701#if defined(DUK_USE_REFERENCE_COUNTING)
56702 duk_hobject *tmp;
56703
56704 DUK_ASSERT(h);
56705 tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
56706 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
56707 DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
56708 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
56709#else
56710 DUK_ASSERT(h);
56711 DUK_UNREF(thr);
56712 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
56713#endif
56714}
56715#line 1 "duk_hobject_pc2line.c"
56716/*
56717 * Helpers for creating and querying pc2line debug data, which
56718 * converts a bytecode program counter to a source line number.
56719 *
56720 * The run-time pc2line data is bit-packed, and documented in:
56721 *
56722 * doc/function-objects.rst
56723 */
56724
56725/* #include duk_internal.h -> already included */
56726
56727#if defined(DUK_USE_PC2LINE)
56728
56729/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
56730DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
56731 duk_hbuffer_dynamic *h_buf;
56732 duk_bitencoder_ctx be_ctx_alloc;
56733 duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
56734 duk_uint32_t *hdr;
56735 duk_size_t new_size;
56736 duk_uint_fast32_t num_header_entries;
56737 duk_uint_fast32_t curr_offset;
56738 duk_int_fast32_t curr_line, next_line, diff_line;
56739 duk_uint_fast32_t curr_pc;
56740 duk_uint_fast32_t hdr_index;
56741
56742 DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
56743
56744 num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
56745 curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
56746
56747 duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset);
56748 h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
56749 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
56750
56751 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
56752 DUK_ASSERT(hdr != NULL);
56753 hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
56754
56755 curr_pc = 0U;
56756 while (curr_pc < length) {
56757 new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
56758 duk_hbuffer_resize(thr, h_buf, new_size);
56759
56760 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
56761 DUK_ASSERT(hdr != NULL);
56762 DUK_ASSERT(curr_pc < length);
56763 hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
56764 curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
56765 hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
56766 hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
56767
56768#if 0
56769 DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
56770 (long) (curr_pc / DUK_PC2LINE_SKIP),
56771 (long) curr_pc,
56772 (long) hdr[hdr_index + 0],
56773 (long) hdr[hdr_index + 1]));
56774#endif
56775
56776 duk_memzero(be_ctx, sizeof(*be_ctx));
56777 be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
56778 be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
56779
56780 for (;;) {
56781 curr_pc++;
56782 if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
56783 (curr_pc >= length) ) { /* end of bytecode */
56784 break;
56785 }
56786 DUK_ASSERT(curr_pc < length);
56787 next_line = (duk_int32_t) instrs[curr_pc].line;
56788 diff_line = next_line - curr_line;
56789
56790#if 0
56791 DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
56792 (long) curr_line, (long) next_line, (long) diff_line));
56793#endif
56794
56795 if (diff_line == 0) {
56796 /* 0 */
56797 duk_be_encode(be_ctx, 0, 1);
56798 } else if (diff_line >= 1 && diff_line <= 4) {
56799 /* 1 0 <2 bits> */
56800 duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4);
56801 } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
56802 /* 1 1 0 <8 bits> */
56803 DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
56804 duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11);
56805 } else {
56806 /* 1 1 1 <32 bits>
56807 * Encode in two parts to avoid bitencode 24-bit limitation
56808 */
56809 duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19);
56810 duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16);
56811 }
56812
56813 curr_line = next_line;
56814 }
56815
56816 duk_be_finish(be_ctx);
56817 DUK_ASSERT(!be_ctx->truncated);
56818
56819 /* be_ctx->offset == length of encoded bitstream */
56820 curr_offset += (duk_uint_fast32_t) be_ctx->offset;
56821 }
56822
56823 /* compact */
56824 new_size = (duk_size_t) curr_offset;
56825 duk_hbuffer_resize(thr, h_buf, new_size);
56826
56827 (void) duk_to_fixed_buffer(thr, -1, NULL);
56828
56829 DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
56830 (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
56831 (duk_tval *) duk_get_tval(thr, -1)));
56832}
56833
56834/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
56835 * it will map to a large PC which is out of bounds and causes a zero to be
56836 * returned.
56837 */
56838DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
56839 duk_bitdecoder_ctx bd_ctx_alloc;
56840 duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
56841 duk_uint32_t *hdr;
56842 duk_uint_fast32_t start_offset;
56843 duk_uint_fast32_t pc_limit;
56844 duk_uint_fast32_t hdr_index;
56845 duk_uint_fast32_t pc_base;
56846 duk_uint_fast32_t n;
56847 duk_uint_fast32_t curr_line;
56848
56849 DUK_ASSERT(buf != NULL);
56850 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
56851 DUK_UNREF(thr);
56852
56853 /*
56854 * Use the index in the header to find the right starting point
56855 */
56856
56857 hdr_index = pc / DUK_PC2LINE_SKIP;
56858 pc_base = hdr_index * DUK_PC2LINE_SKIP;
56859 n = pc - pc_base;
56860
56861 if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
56862 DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
56863 goto pc2line_error;
56864 }
56865
56866 hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
56867 pc_limit = hdr[0];
56868 if (pc >= pc_limit) {
56869 /* Note: pc is unsigned and cannot be negative */
56870 DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
56871 (long) pc, (long) pc_limit));
56872 goto pc2line_error;
56873 }
56874
56875 curr_line = hdr[1 + hdr_index * 2];
56876 start_offset = hdr[1 + hdr_index * 2 + 1];
56877 if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
56878 DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
56879 (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
56880 goto pc2line_error;
56881 }
56882
56883 /*
56884 * Iterate the bitstream (line diffs) until PC is reached
56885 */
56886
56887 duk_memzero(bd_ctx, sizeof(*bd_ctx));
56888 bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
56889 bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
56890
56891#if 0
56892 DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
56893 (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
56894#endif
56895
56896 while (n > 0) {
56897#if 0
56898 DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
56899#endif
56900
56901 if (duk_bd_decode_flag(bd_ctx)) {
56902 if (duk_bd_decode_flag(bd_ctx)) {
56903 if (duk_bd_decode_flag(bd_ctx)) {
56904 /* 1 1 1 <32 bits> */
56905 duk_uint_fast32_t t;
56906 t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
56907 t = (t << 16) + duk_bd_decode(bd_ctx, 16);
56908 curr_line = t;
56909 } else {
56910 /* 1 1 0 <8 bits> */
56911 duk_uint_fast32_t t;
56912 t = duk_bd_decode(bd_ctx, 8);
56913 curr_line = curr_line + t - 0x80;
56914 }
56915 } else {
56916 /* 1 0 <2 bits> */
56917 duk_uint_fast32_t t;
56918 t = duk_bd_decode(bd_ctx, 2);
56919 curr_line = curr_line + t + 1;
56920 }
56921 } else {
56922 /* 0: no change */
56923 }
56924
56925 n--;
56926 }
56927
56928 DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
56929 return curr_line;
56930
56931 pc2line_error:
56932 DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
56933 return 0;
56934}
56935
56936DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) {
56937 duk_hbuffer_fixed *pc2line;
56938 duk_uint_fast32_t line;
56939
56940 /* XXX: now that pc2line is used by the debugger quite heavily in
56941 * checked execution, this should be optimized to avoid value stack
56942 * and perhaps also implement some form of pc2line caching (see
56943 * future work in debugger.rst).
56944 */
56945
56946 duk_xget_owndataprop_stridx_short(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
56947 pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1);
56948 if (pc2line != NULL) {
56949 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
56950 line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
56951 } else {
56952 line = 0;
56953 }
56954 duk_pop(thr);
56955
56956 return line;
56957}
56958
56959#endif /* DUK_USE_PC2LINE */
56960#line 1 "duk_hobject_props.c"
56961/*
56962 * duk_hobject property access functionality.
56963 *
56964 * This is very central functionality for size, performance, and compliance.
56965 * It is also rather intricate; see hobject-algorithms.rst for discussion on
56966 * the algorithms and memory-management.rst for discussion on refcounts and
56967 * side effect issues.
56968 *
56969 * Notes:
56970 *
56971 * - It might be tempting to assert "refcount nonzero" for objects
56972 * being operated on, but that's not always correct: objects with
56973 * a zero refcount may be operated on by the refcount implementation
56974 * (finalization) for instance. Hence, no refcount assertions are made.
56975 *
56976 * - Many operations (memory allocation, identifier operations, etc)
56977 * may cause arbitrary side effects (e.g. through GC and finalization).
56978 * These side effects may invalidate duk_tval pointers which point to
56979 * areas subject to reallocation (like value stack). Heap objects
56980 * themselves have stable pointers. Holding heap object pointers or
56981 * duk_tval copies is not problematic with respect to side effects;
56982 * care must be taken when holding and using argument duk_tval pointers.
56983 *
56984 * - If a finalizer is executed, it may operate on the the same object
56985 * we're currently dealing with. For instance, the finalizer might
56986 * delete a certain property which has already been looked up and
56987 * confirmed to exist. Ideally finalizers would be disabled if GC
56988 * happens during property access. At the moment property table realloc
56989 * disables finalizers, and all DECREFs may cause arbitrary changes so
56990 * handle DECREF carefully.
56991 *
56992 * - The order of operations for a DECREF matters. When DECREF is executed,
56993 * the entire object graph must be consistent; note that a refzero may
56994 * lead to a mark-and-sweep through a refcount finalizer. Use NORZ macros
56995 * and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard.
56996 */
56997
56998/*
56999 * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
57000 * might be more appropriate.
57001 */
57002
57003/* #include duk_internal.h -> already included */
57004
57005/*
57006 * Local defines
57007 */
57008
57009#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
57010
57011/* Marker values for hash part. */
57012#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
57013#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
57014
57015/* Valstack space that suffices for all local calls, excluding any recursion
57016 * into ECMAScript or Duktape/C calls (Proxy, getters, etc).
57017 */
57018#define DUK__VALSTACK_SPACE 10
57019
57020/* Valstack space allocated especially for proxy lookup which does a
57021 * recursive property lookup.
57022 */
57023#define DUK__VALSTACK_PROXY_LOOKUP 20
57024
57025/*
57026 * Local prototypes
57027 */
57028
57029DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
57030DUK_LOCAL_DECL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag);
57031DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
57032
57033DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, duk_hobject *obj, duk_uint32_t old_len, duk_uint32_t new_len, duk_bool_t force_flag, duk_uint32_t *out_result_len);
57034DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
57035
57036DUK_LOCAL_DECL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
57037DUK_LOCAL_DECL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags);
57038
57039DUK_LOCAL_DECL void duk__abandon_array_part(duk_hthread *thr, duk_hobject *obj);
57040DUK_LOCAL_DECL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx);
57041
57042/*
57043 * Misc helpers
57044 */
57045
57046/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns
57047 * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
57048 * index.
57049 */
57050/* XXX: for fastints, could use a variant which assumes a double duk_tval
57051 * (and doesn't need to check for fastint again).
57052 */
57053DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
57054 duk_double_t dbl;
57055 duk_uint32_t idx;
57056
57057 DUK_ASSERT(tv != NULL);
57058 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
57059
57060 /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
57061 * in canonical form and thus an array index.
57062 */
57063 dbl = DUK_TVAL_GET_NUMBER(tv);
57064 idx = (duk_uint32_t) dbl;
57065 if (duk_double_equals((duk_double_t) idx, dbl)) {
57066 /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF,
57067 * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
57068 */
57069 return idx;
57070 }
57071 return DUK__NO_ARRAY_INDEX;
57072}
57073
57074#if defined(DUK_USE_FASTINT)
57075/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
57076DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
57077 duk_int64_t t;
57078
57079 DUK_ASSERT(tv != NULL);
57080 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
57081
57082 t = DUK_TVAL_GET_FASTINT(tv);
57083 if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) {
57084 /* Catches >0x100000000 and negative values. */
57085 return DUK__NO_ARRAY_INDEX;
57086 }
57087
57088 /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
57089 * but will then match DUK__NO_ARRAY_INDEX.
57090 */
57091 return (duk_uint32_t) t;
57092}
57093#endif /* DUK_USE_FASTINT */
57094
57095/* Convert a duk_tval on the value stack (in a trusted index we don't validate)
57096 * to a string or symbol using ES2015 ToPropertyKey():
57097 * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey.
57098 *
57099 * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX
57100 * if not).
57101 */
57102DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) {
57103 duk_uint32_t arr_idx;
57104 duk_hstring *h;
57105 duk_tval *tv_dst;
57106
57107 DUK_ASSERT(thr != NULL);
57108 DUK_ASSERT(out_h != NULL);
57109 DUK_ASSERT(duk_is_valid_index(thr, idx));
57110 DUK_ASSERT(idx < 0);
57111
57112 /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just
57113 * ToString()) involves a ToPrimitive(), a symbol check, and finally
57114 * a ToString(). Figure out the best way to have a good fast path
57115 * but still be compliant and share code.
57116 */
57117
57118 tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx); /* intentionally unvalidated */
57119 if (DUK_TVAL_IS_STRING(tv_dst)) {
57120 /* Most important path: strings and plain symbols are used as
57121 * is. For symbols the array index check below is unnecessary
57122 * (they're never valid array indices) but checking that the
57123 * string is a symbol would make the plain string path slower
57124 * unnecessarily.
57125 */
57126 h = DUK_TVAL_GET_STRING(tv_dst);
57127 } else {
57128 h = duk_to_property_key_hstring(thr, idx);
57129 }
57130 DUK_ASSERT(h != NULL);
57131 *out_h = h;
57132
57133 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
57134 return arr_idx;
57135}
57136
57137DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) {
57138 duk_push_tval(thr, tv_key); /* XXX: could use an unsafe push here */
57139 return duk__to_property_key(thr, -1, out_h);
57140}
57141
57142/* String is an own (virtual) property of a plain buffer. */
57143DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) {
57144 DUK_UNREF(thr);
57145
57146 /* Virtual index properties. Checking explicitly for
57147 * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary
57148 * because DUK__NO_ARRAY_INDEXi is always larger than
57149 * maximum allowed buffer size.
57150 */
57151 DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf));
57152 if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) {
57153 return 1;
57154 }
57155
57156 /* Other virtual properties. */
57157 return (key == DUK_HTHREAD_STRING_LENGTH(thr));
57158}
57159
57160/*
57161 * Helpers for managing property storage size
57162 */
57163
57164/* Get default hash part size for a certain entry part size. */
57165#if defined(DUK_USE_HOBJECT_HASH_PART)
57166DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
57167 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
57168
57169 if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
57170 duk_uint32_t res;
57171 duk_uint32_t tmp;
57172
57173 /* Hash size should be 2^N where N is chosen so that 2^N is
57174 * larger than e_size. Extra shifting is used to ensure hash
57175 * is relatively sparse.
57176 */
57177 tmp = e_size;
57178 res = 2; /* Result will be 2 ** (N + 1). */
57179 while (tmp >= 0x40) {
57180 tmp >>= 6;
57181 res <<= 6;
57182 }
57183 while (tmp != 0) {
57184 tmp >>= 1;
57185 res <<= 1;
57186 }
57187 DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */
57188 DUK_ASSERT(res > e_size);
57189 return res;
57190 } else {
57191 return 0;
57192 }
57193}
57194#endif /* USE_PROP_HASH_PART */
57195
57196/* Get minimum entry part growth for a certain size. */
57197DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
57198 duk_uint32_t res;
57199
57200 res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR;
57201 DUK_ASSERT(res >= 1); /* important for callers */
57202 return res;
57203}
57204
57205/* Get minimum array part growth for a certain size. */
57206DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
57207 duk_uint32_t res;
57208
57209 res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR;
57210 DUK_ASSERT(res >= 1); /* important for callers */
57211 return res;
57212}
57213
57214/* Count actually used entry part entries (non-NULL keys). */
57215DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
57216 duk_uint_fast32_t i;
57217 duk_uint_fast32_t n = 0;
57218 duk_hstring **e;
57219
57220 DUK_ASSERT(obj != NULL);
57221 DUK_UNREF(thr);
57222
57223 e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
57224 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
57225 if (*e++) {
57226 n++;
57227 }
57228 }
57229 return (duk_uint32_t) n;
57230}
57231
57232/* Count actually used array part entries and array minimum size.
57233 * NOTE: 'out_min_size' can be computed much faster by starting from the
57234 * end and breaking out early when finding first used entry, but this is
57235 * not needed now.
57236 */
57237DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
57238 duk_uint_fast32_t i;
57239 duk_uint_fast32_t used = 0;
57240 duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */
57241 duk_tval *a;
57242
57243 DUK_ASSERT(obj != NULL);
57244 DUK_ASSERT(out_used != NULL);
57245 DUK_ASSERT(out_min_size != NULL);
57246 DUK_UNREF(thr);
57247
57248 a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
57249 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
57250 duk_tval *tv = a++;
57251 if (!DUK_TVAL_IS_UNUSED(tv)) {
57252 used++;
57253 highest_idx = i;
57254 }
57255 }
57256
57257 /* Initial value for highest_idx is -1 coerced to unsigned. This
57258 * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
57259 * for out_min_size as intended.
57260 */
57261
57262 *out_used = (duk_uint32_t) used;
57263 *out_min_size = (duk_uint32_t) (highest_idx + 1); /* 0 if no used entries */
57264}
57265
57266/* Check array density and indicate whether or not the array part should be abandoned. */
57267DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
57268 /*
57269 * Array abandon check; abandon if:
57270 *
57271 * new_used / new_size < limit
57272 * new_used < limit * new_size || limit is 3 bits fixed point
57273 * new_used < limit' / 8 * new_size || *8
57274 * 8*new_used < limit' * new_size || :8
57275 * new_used < limit' * (new_size / 8)
57276 *
57277 * Here, new_used = a_used, new_size = a_size.
57278 *
57279 * Note: some callers use approximate values for a_used and/or a_size
57280 * (e.g. dropping a '+1' term). This doesn't affect the usefulness
57281 * of the check, but may confuse debugging.
57282 */
57283
57284 return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3));
57285}
57286
57287/* Fast check for extending array: check whether or not a slow density check is required. */
57288DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
57289 duk_uint32_t new_size_min;
57290
57291 /*
57292 * In a fast check we assume old_size equals old_used (i.e., existing
57293 * array is fully dense).
57294 *
57295 * Slow check if:
57296 *
57297 * (new_size - old_size) / old_size > limit
57298 * new_size - old_size > limit * old_size
57299 * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point
57300 * new_size > (1 + (limit' / 8)) * old_size || * 8
57301 * 8 * new_size > (8 + limit') * old_size || : 8
57302 * new_size > (8 + limit') * (old_size / 8)
57303 * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase
57304 * arr_idx + 1 > limit'' * (old_size / 8)
57305 *
57306 * This check doesn't work well for small values, so old_size is rounded
57307 * up for the check (and the '+ 1' of arr_idx can be ignored in practice):
57308 *
57309 * arr_idx > limit'' * ((old_size + 7) / 8)
57310 */
57311
57312 new_size_min = arr_idx + 1;
57313 return (new_size_min >= DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE) &&
57314 (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
57315}
57316
57317DUK_LOCAL duk_bool_t duk__abandon_array_check(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) {
57318 duk_uint32_t min_size;
57319 duk_uint32_t old_used;
57320 duk_uint32_t old_size;
57321
57322 if (!duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(obj))) {
57323 DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
57324 return 0;
57325 }
57326
57327 duk__compute_a_stats(thr, obj, &old_used, &old_size);
57328
57329 DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
57330 (long) old_used, (long) old_size, (long) arr_idx));
57331
57332 min_size = arr_idx + 1;
57333#if defined(DUK_USE_OBJSIZES16)
57334 if (min_size > DUK_UINT16_MAX) {
57335 goto do_abandon;
57336 }
57337#endif
57338 DUK_UNREF(min_size);
57339
57340 /* Note: intentionally use approximations to shave a few instructions:
57341 * a_used = old_used (accurate: old_used + 1)
57342 * a_size = arr_idx (accurate: arr_idx + 1)
57343 */
57344 if (duk__abandon_array_density_check(old_used, arr_idx)) {
57345 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
57346 "decided to abandon array part (would become too sparse)"));
57347
57348 /* Abandoning requires a props allocation resize and
57349 * 'rechecks' the valstack, invalidating any existing
57350 * valstack value pointers.
57351 */
57352 goto do_abandon;
57353 }
57354
57355 DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
57356 return 0;
57357
57358 do_abandon:
57359 duk__abandon_array_part(thr, obj);
57360 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj));
57361 return 1;
57362}
57363
57364DUK_LOCAL duk_tval *duk__obtain_arridx_slot_slowpath(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) {
57365 /*
57366 * Array needs to grow, but we don't want it becoming too sparse.
57367 * If it were to become sparse, abandon array part, moving all
57368 * array entries into the entries part (for good).
57369 *
57370 * Since we don't keep track of actual density (used vs. size) of
57371 * the array part, we need to estimate somehow. The check is made
57372 * in two parts:
57373 *
57374 * - Check whether the resize need is small compared to the
57375 * current size (relatively); if so, resize without further
57376 * checking (essentially we assume that the original part is
57377 * "dense" so that the result would be dense enough).
57378 *
57379 * - Otherwise, compute the resize using an actual density
57380 * measurement based on counting the used array entries.
57381 */
57382
57383 DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
57384 "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
57385 (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(obj)));
57386
57387 if (DUK_UNLIKELY(duk__abandon_array_check(thr, arr_idx, obj) != 0)) {
57388 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj));
57389 return NULL;
57390 }
57391
57392 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
57393 "decided to extend current allocation"));
57394
57395 /* In principle it's possible to run out of memory extending the
57396 * array but with the allocation going through if we were to abandon
57397 * the array part and try again. In practice this should be rare
57398 * because abandoned arrays have a higher per-entry footprint.
57399 */
57400
57401 duk__grow_props_for_array_item(thr, obj, arr_idx);
57402
57403 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(obj));
57404 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
57405 return DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
57406}
57407
57408DUK_LOCAL DUK_INLINE duk_tval *duk__obtain_arridx_slot(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) {
57409 if (DUK_LIKELY(arr_idx < DUK_HOBJECT_GET_ASIZE(obj))) {
57410 return DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
57411 } else {
57412 return duk__obtain_arridx_slot_slowpath(thr, arr_idx, obj);
57413 }
57414}
57415
57416/*
57417 * Proxy helpers
57418 */
57419
57420#if defined(DUK_USE_ES6_PROXY)
57421DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
57422 duk_hproxy *h_proxy;
57423
57424 DUK_ASSERT(obj != NULL);
57425 DUK_ASSERT(out_target != NULL);
57426 DUK_ASSERT(out_handler != NULL);
57427
57428 /* Caller doesn't need to check exotic proxy behavior (but does so for
57429 * some fast paths).
57430 */
57431 if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) {
57432 return 0;
57433 }
57434 h_proxy = (duk_hproxy *) obj;
57435 DUK_HPROXY_ASSERT_VALID(h_proxy);
57436
57437 DUK_ASSERT(h_proxy->handler != NULL);
57438 DUK_ASSERT(h_proxy->target != NULL);
57439 *out_handler = h_proxy->handler;
57440 *out_target = h_proxy->target;
57441
57442 return 1;
57443}
57444#endif /* DUK_USE_ES6_PROXY */
57445
57446/* Get Proxy target object. If the argument is not a Proxy, return it as is.
57447 * If a Proxy is revoked, an error is thrown.
57448 */
57449#if defined(DUK_USE_ES6_PROXY)
57450DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) {
57451 DUK_ASSERT(obj != NULL);
57452
57453 /* Resolve Proxy targets until Proxy chain ends. No explicit check for
57454 * a Proxy loop: user code cannot create such a loop (it would only be
57455 * possible by editing duk_hproxy references directly).
57456 */
57457
57458 while (DUK_HOBJECT_IS_PROXY(obj)) {
57459 duk_hproxy *h_proxy;
57460
57461 h_proxy = (duk_hproxy *) obj;
57462 DUK_HPROXY_ASSERT_VALID(h_proxy);
57463 obj = h_proxy->target;
57464 DUK_ASSERT(obj != NULL);
57465 }
57466
57467 DUK_ASSERT(obj != NULL);
57468 return obj;
57469}
57470#endif /* DUK_USE_ES6_PROXY */
57471
57472#if defined(DUK_USE_ES6_PROXY)
57473DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) {
57474 duk_hobject *h_handler;
57475
57476 DUK_ASSERT(thr != NULL);
57477 DUK_ASSERT(obj != NULL);
57478 DUK_ASSERT(tv_key != NULL);
57479 DUK_ASSERT(out_target != NULL);
57480
57481 if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) {
57482 return 0;
57483 }
57484 DUK_ASSERT(*out_target != NULL);
57485 DUK_ASSERT(h_handler != NULL);
57486
57487 /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
57488 * normal property set/get which would allow a proxy handler to interfere with
57489 * such behavior and to get access to internal key strings. This is not a problem
57490 * as such because internal key strings can be created in other ways too (e.g.
57491 * through buffers). The best fix is to change Duktape internal lookups to
57492 * skip proxy behavior. Until that, internal property accesses bypass the
57493 * proxy and are applied to the target (as if the handler did not exist).
57494 * This has some side effects, see test-bi-proxy-internal-keys.js.
57495 */
57496
57497 if (DUK_TVAL_IS_STRING(tv_key)) {
57498 duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
57499 DUK_ASSERT(h_key != NULL);
57500 if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
57501 /* Symbol accesses must go through proxy lookup in ES2015.
57502 * Hidden symbols behave like Duktape 1.x internal keys
57503 * and currently won't.
57504 */
57505 DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target"));
57506 return 0;
57507 }
57508 }
57509
57510 /* The handler is looked up with a normal property lookup; it may be an
57511 * accessor or the handler object itself may be a proxy object. If the
57512 * handler is a proxy, we need to extend the valstack as we make a
57513 * recursive proxy check without a function call in between (in fact
57514 * there is no limit to the potential recursion here).
57515 *
57516 * (For sanity, proxy creation rejects another proxy object as either
57517 * the handler or the target at the moment so recursive proxy cases
57518 * are not realized now.)
57519 */
57520
57521 /* XXX: C recursion limit if proxies are allowed as handler/target values */
57522
57523 duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP);
57524 duk_push_hobject(thr, h_handler);
57525 if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) {
57526 /* -> [ ... handler trap ] */
57527 duk_insert(thr, -2); /* -> [ ... trap handler ] */
57528
57529 /* stack prepped for func call: [ ... trap handler ] */
57530 return 1;
57531 } else {
57532 duk_pop_2_unsafe(thr);
57533 return 0;
57534 }
57535}
57536#endif /* DUK_USE_ES6_PROXY */
57537
57538/*
57539 * Reallocate property allocation, moving properties to the new allocation.
57540 *
57541 * Includes key compaction, rehashing, and can also optionally abandon
57542 * the array part, 'migrating' array entries into the beginning of the
57543 * new entry part.
57544 *
57545 * There is no support for in-place reallocation or just compacting keys
57546 * without resizing the property allocation. This is intentional to keep
57547 * code size minimal, but would be useful future work.
57548 *
57549 * The implementation is relatively straightforward, except for the array
57550 * abandonment process. Array abandonment requires that new string keys
57551 * are interned, which may trigger GC. All keys interned so far must be
57552 * reachable for GC at all times and correctly refcounted for; valstack is
57553 * used for that now.
57554 *
57555 * Also, a GC triggered during this reallocation process must not interfere
57556 * with the object being resized. This is currently controlled by preventing
57557 * finalizers (as they may affect ANY object) and object compaction in
57558 * mark-and-sweep. It would suffice to protect only this particular object
57559 * from compaction, however. DECREF refzero cascades are side effect free
57560 * and OK.
57561 *
57562 * Note: because we need to potentially resize the valstack (as part
57563 * of abandoning the array part), any tval pointers to the valstack
57564 * will become invalid after this call.
57565 */
57566
57567DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
57568 duk_hobject *obj,
57569 duk_uint32_t new_e_size,
57570 duk_uint32_t new_a_size,
57571 duk_uint32_t new_h_size,
57572 duk_bool_t abandon_array) {
57573 duk_small_uint_t prev_ms_base_flags;
57574 duk_uint32_t new_alloc_size;
57575 duk_uint32_t new_e_size_adjusted;
57576 duk_uint8_t *new_p;
57577 duk_hstring **new_e_k;
57578 duk_propvalue *new_e_pv;
57579 duk_uint8_t *new_e_f;
57580 duk_tval *new_a;
57581 duk_uint32_t *new_h;
57582 duk_uint32_t new_e_next;
57583 duk_uint_fast32_t i;
57584 duk_size_t array_copy_size;
57585#if defined(DUK_USE_ASSERTIONS)
57586 duk_bool_t prev_error_not_allowed;
57587#endif
57588
57589 DUK_ASSERT(thr != NULL);
57590 DUK_ASSERT(obj != NULL);
57591 DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
57592 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
57593 DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing,
57594 * intentionally use unadjusted new_e_size
57595 */
57596 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
57597 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57598
57599 DUK_STATS_INC(thr->heap, stats_object_realloc_props);
57600
57601 /*
57602 * Pre resize assertions.
57603 */
57604
57605#if defined(DUK_USE_ASSERTIONS)
57606 /* XXX: pre-checks (such as no duplicate keys) */
57607#endif
57608
57609 /*
57610 * For property layout 1, tweak e_size to ensure that the whole entry
57611 * part (key + val + flags) is a suitable multiple for alignment
57612 * (platform specific).
57613 *
57614 * Property layout 2 does not require this tweaking and is preferred
57615 * on low RAM platforms requiring alignment.
57616 */
57617
57618#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
57619 DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
57620 new_e_size_adjusted = new_e_size;
57621#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
57622 DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
57623 new_e_size_adjusted = new_e_size;
57624#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
57625 new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) &
57626 (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U));
57627 DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
57628 (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
57629 DUK_ASSERT(new_e_size_adjusted >= new_e_size);
57630#else
57631#error invalid hobject layout defines
57632#endif
57633
57634 /*
57635 * Debug logging after adjustment.
57636 */
57637
57638 DUK_DDD(DUK_DDDPRINT("attempt to resize hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to "
57639 "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
57640 (void *) obj,
57641 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
57642 DUK_HOBJECT_GET_ASIZE(obj),
57643 DUK_HOBJECT_GET_HSIZE(obj)),
57644 (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
57645 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
57646 (long) DUK_HOBJECT_GET_ESIZE(obj),
57647 (long) DUK_HOBJECT_GET_ENEXT(obj),
57648 (long) DUK_HOBJECT_GET_ASIZE(obj),
57649 (long) DUK_HOBJECT_GET_HSIZE(obj),
57650 (long) new_e_size_adjusted,
57651 (long) new_a_size,
57652 (long) new_h_size,
57653 (long) abandon_array,
57654 (long) new_e_size));
57655
57656 /*
57657 * Property count check. This is the only point where we ensure that
57658 * we don't get more (allocated) property space that we can handle.
57659 * There aren't hard limits as such, but some algorithms may fail
57660 * if we get too close to the 4G property limit.
57661 *
57662 * Since this works based on allocation size (not actually used size),
57663 * the limit is a bit approximate but good enough in practice.
57664 */
57665
57666 if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
57667 DUK_ERROR_ALLOC_FAILED(thr);
57668 DUK_WO_NORETURN(return;);
57669 }
57670#if defined(DUK_USE_OBJSIZES16)
57671 if (new_e_size_adjusted > DUK_UINT16_MAX || new_a_size > DUK_UINT16_MAX) {
57672 /* If caller gave us sizes larger than what we can store,
57673 * fail memory safely with an internal error rather than
57674 * truncating the sizes.
57675 */
57676 DUK_ERROR_INTERNAL(thr);
57677 DUK_WO_NORETURN(return;);
57678 }
57679#endif
57680
57681 /*
57682 * Compute new alloc size and alloc new area.
57683 *
57684 * The new area is not tracked in the heap at all, so it's critical
57685 * we get to free/keep it in a controlled manner.
57686 */
57687
57688#if defined(DUK_USE_ASSERTIONS)
57689 /* Whole path must be error throw free, but we may be called from
57690 * within error handling so can't assert for error_not_allowed == 0.
57691 */
57692 prev_error_not_allowed = thr->heap->error_not_allowed;
57693 thr->heap->error_not_allowed = 1;
57694#endif
57695 prev_ms_base_flags = thr->heap->ms_base_flags;
57696 thr->heap->ms_base_flags |=
57697 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */
57698 thr->heap->pf_prevent_count++; /* Avoid finalizers. */
57699 DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
57700
57701 new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
57702 DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
57703 if (new_alloc_size == 0) {
57704 DUK_ASSERT(new_e_size_adjusted == 0);
57705 DUK_ASSERT(new_a_size == 0);
57706 DUK_ASSERT(new_h_size == 0);
57707 new_p = NULL;
57708 } else {
57709 /* Alloc may trigger mark-and-sweep but no compaction, and
57710 * cannot throw.
57711 */
57712#if 0 /* XXX: inject test */
57713 if (1) {
57714 new_p = NULL;
57715 goto alloc_failed;
57716 }
57717#endif
57718 new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size);
57719 if (new_p == NULL) {
57720 /* NULL always indicates alloc failure because
57721 * new_alloc_size > 0.
57722 */
57723 goto alloc_failed;
57724 }
57725 }
57726
57727 /* Set up pointers to the new property area: this is hidden behind a macro
57728 * because it is memory layout specific.
57729 */
57730 DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
57731 new_e_size_adjusted, new_a_size, new_h_size);
57732 DUK_UNREF(new_h); /* happens when hash part dropped */
57733 new_e_next = 0;
57734
57735 /* if new_p == NULL, all of these pointers are NULL */
57736 DUK_ASSERT((new_p != NULL) ||
57737 (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
57738 new_a == NULL && new_h == NULL));
57739
57740 DUK_DDD(DUK_DDDPRINT("new alloc size %ld, new_e_k=%p, new_e_pv=%p, new_e_f=%p, new_a=%p, new_h=%p",
57741 (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
57742 (void *) new_a, (void *) new_h));
57743
57744 /*
57745 * Migrate array part to start of entries if requested.
57746 *
57747 * Note: from an enumeration perspective the order of entry keys matters.
57748 * Array keys should appear wherever they appeared before the array abandon
57749 * operation. (This no longer matters much because keys are ES2015 sorted.)
57750 */
57751
57752 if (abandon_array) {
57753 /* Assuming new_a_size == 0, and that entry part contains
57754 * no conflicting keys, refcounts do not need to be adjusted for
57755 * the values, as they remain exactly the same.
57756 *
57757 * The keys, however, need to be interned, incref'd, and be
57758 * reachable for GC. Any intern attempt may trigger a GC and
57759 * claim any non-reachable strings, so every key must be reachable
57760 * at all times. Refcounts must be correct to satisfy refcount
57761 * assertions.
57762 *
57763 * A longjmp must not occur here, as the new_p allocation would
57764 * leak. Refcounts would come out correctly as the interned
57765 * strings are valstack tracked.
57766 */
57767 DUK_ASSERT(new_a_size == 0);
57768
57769 DUK_STATS_INC(thr->heap, stats_object_abandon_array);
57770
57771 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
57772 duk_tval *tv1;
57773 duk_tval *tv2;
57774 duk_hstring *key;
57775
57776 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
57777
57778 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
57779 if (DUK_TVAL_IS_UNUSED(tv1)) {
57780 continue;
57781 }
57782
57783 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
57784 new_e_pv != NULL && new_e_f != NULL);
57785
57786 /*
57787 * Intern key via the valstack to ensure reachability behaves
57788 * properly. We must avoid longjmp's here so use non-checked
57789 * primitives.
57790 *
57791 * Note: duk_check_stack() potentially reallocs the valstack,
57792 * invalidating any duk_tval pointers to valstack. Callers
57793 * must be careful.
57794 */
57795
57796#if 0 /* XXX: inject test */
57797 if (1) {
57798 goto abandon_error;
57799 }
57800#endif
57801 /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which
57802 * is generous.
57803 */
57804 if (!duk_check_stack(thr, 1)) {
57805 goto abandon_error;
57806 }
57807 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
57808 key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i);
57809 if (key == NULL) {
57810 goto abandon_error;
57811 }
57812 duk_push_hstring(thr, key); /* keep key reachable for GC etc; guaranteed not to fail */
57813
57814 /* Key is now reachable in the valstack, don't INCREF
57815 * the new allocation yet (we'll steal the refcounts
57816 * from the value stack once all keys are done).
57817 */
57818
57819 new_e_k[new_e_next] = key;
57820 tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
57821 DUK_TVAL_SET_TVAL(tv2, tv1);
57822 new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
57823 DUK_PROPDESC_FLAG_ENUMERABLE |
57824 DUK_PROPDESC_FLAG_CONFIGURABLE;
57825 new_e_next++;
57826
57827 /* Note: new_e_next matches pushed temp key count, and nothing can
57828 * fail above between the push and this point.
57829 */
57830 }
57831
57832 /* Steal refcounts from value stack. */
57833 DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
57834 duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next);
57835 }
57836
57837 /*
57838 * Copy keys and values in the entry part (compacting them at the same time).
57839 */
57840
57841 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
57842 duk_hstring *key;
57843
57844 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
57845
57846 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
57847 if (key == NULL) {
57848 continue;
57849 }
57850
57851 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
57852 new_e_pv != NULL && new_e_f != NULL);
57853
57854 new_e_k[new_e_next] = key;
57855 new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
57856 new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
57857 new_e_next++;
57858 }
57859 /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
57860
57861 /*
57862 * Copy array elements to new array part. If the new array part is
57863 * larger, initialize the unused entries as UNUSED because they are
57864 * GC reachable.
57865 */
57866
57867#if defined(DUK_USE_ASSERTIONS)
57868 /* Caller must have decref'd values above new_a_size (if that is necessary). */
57869 if (!abandon_array) {
57870 for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
57871 duk_tval *tv;
57872 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
57873 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
57874 }
57875 }
57876#endif
57877 if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
57878 array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj);
57879 } else {
57880 array_copy_size = sizeof(duk_tval) * new_a_size;
57881 }
57882
57883 DUK_ASSERT(new_a != NULL || array_copy_size == 0U);
57884 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U);
57885 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U);
57886 duk_memcpy_unsafe((void *) new_a,
57887 (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
57888 array_copy_size);
57889
57890 for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
57891 duk_tval *tv = &new_a[i];
57892 DUK_TVAL_SET_UNUSED(tv);
57893 }
57894
57895 /*
57896 * Rebuild the hash part always from scratch (guaranteed to finish
57897 * as long as caller gave consistent parameters).
57898 *
57899 * Any resize of hash part requires rehashing. In addition, by rehashing
57900 * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
57901 * to ensuring the hash part never fills up.
57902 */
57903
57904#if defined(DUK_USE_HOBJECT_HASH_PART)
57905 if (new_h_size == 0) {
57906 DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
57907 } else {
57908 duk_uint32_t mask;
57909
57910 DUK_ASSERT(new_h != NULL);
57911
57912 /* fill new_h with u32 0xff = UNUSED */
57913 DUK_ASSERT(new_h_size > 0);
57914 duk_memset(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
57915
57916 DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
57917
57918 mask = new_h_size - 1;
57919 for (i = 0; i < new_e_next; i++) {
57920 duk_hstring *key = new_e_k[i];
57921 duk_uint32_t j, step;
57922
57923 DUK_ASSERT(key != NULL);
57924 j = DUK_HSTRING_GET_HASH(key) & mask;
57925 step = 1; /* Cache friendly but clustering prone. */
57926
57927 for (;;) {
57928 DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
57929 if (new_h[j] == DUK__HASH_UNUSED) {
57930 DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
57931 new_h[j] = (duk_uint32_t) i;
57932 break;
57933 }
57934 DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
57935 j = (j + step) & mask;
57936
57937 /* Guaranteed to finish (hash is larger than #props). */
57938 }
57939 }
57940 }
57941#endif /* DUK_USE_HOBJECT_HASH_PART */
57942
57943 /*
57944 * Nice debug log.
57945 */
57946
57947 DUK_DD(DUK_DDPRINT("resized hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to "
57948 "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
57949 (void *) obj,
57950 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
57951 DUK_HOBJECT_GET_ASIZE(obj),
57952 DUK_HOBJECT_GET_HSIZE(obj)),
57953 (long) new_alloc_size,
57954 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
57955 (long) DUK_HOBJECT_GET_ESIZE(obj),
57956 (long) DUK_HOBJECT_GET_ENEXT(obj),
57957 (long) DUK_HOBJECT_GET_ASIZE(obj),
57958 (long) DUK_HOBJECT_GET_HSIZE(obj),
57959 (void *) new_p,
57960 (long) new_e_size_adjusted,
57961 (long) new_e_next,
57962 (long) new_a_size,
57963 (long) new_h_size,
57964 (long) abandon_array,
57965 (long) new_e_size));
57966
57967 /*
57968 * All done, switch properties ('p') allocation to new one.
57969 */
57970
57971 DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
57972 DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
57973 DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
57974 DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
57975 DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
57976 DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
57977
57978 /* Clear array part flag only after switching. */
57979 if (abandon_array) {
57980 DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
57981 }
57982
57983 DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
57984
57985 DUK_ASSERT(thr->heap->pf_prevent_count > 0);
57986 thr->heap->pf_prevent_count--;
57987 thr->heap->ms_base_flags = prev_ms_base_flags;
57988#if defined(DUK_USE_ASSERTIONS)
57989 DUK_ASSERT(thr->heap->error_not_allowed == 1);
57990 thr->heap->error_not_allowed = prev_error_not_allowed;
57991#endif
57992
57993 /*
57994 * Post resize assertions.
57995 */
57996
57997#if defined(DUK_USE_ASSERTIONS)
57998 /* XXX: post-checks (such as no duplicate keys) */
57999#endif
58000 return;
58001
58002 /*
58003 * Abandon array failed. We don't need to DECREF anything
58004 * because the references in the new allocation are not
58005 * INCREF'd until abandon is complete. The string interned
58006 * keys are on the value stack and are handled normally by
58007 * unwind.
58008 */
58009
58010 abandon_error:
58011 alloc_failed:
58012 DUK_D(DUK_DPRINT("object property table resize failed"));
58013
58014 DUK_FREE_CHECKED(thr, new_p); /* OK for NULL. */
58015
58016 thr->heap->pf_prevent_count--;
58017 thr->heap->ms_base_flags = prev_ms_base_flags;
58018#if defined(DUK_USE_ASSERTIONS)
58019 DUK_ASSERT(thr->heap->error_not_allowed == 1);
58020 thr->heap->error_not_allowed = prev_error_not_allowed;
58021#endif
58022
58023 DUK_ERROR_ALLOC_FAILED(thr);
58024 DUK_WO_NORETURN(return;);
58025}
58026
58027/*
58028 * Helpers to resize properties allocation on specific needs.
58029 */
58030
58031DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr,
58032 duk_hobject *obj,
58033 duk_uint32_t new_e_size) {
58034 duk_uint32_t old_e_size;
58035 duk_uint32_t new_a_size;
58036 duk_uint32_t new_h_size;
58037
58038 DUK_ASSERT(thr != NULL);
58039 DUK_ASSERT(obj != NULL);
58040
58041 old_e_size = DUK_HOBJECT_GET_ESIZE(obj);
58042 if (old_e_size > new_e_size) {
58043 new_e_size = old_e_size;
58044 }
58045#if defined(DUK_USE_HOBJECT_HASH_PART)
58046 new_h_size = duk__get_default_h_size(new_e_size);
58047#else
58048 new_h_size = 0;
58049#endif
58050 new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
58051
58052 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
58053}
58054
58055/* Grow entry part allocation for one additional entry. */
58056DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
58057 duk_uint32_t old_e_used; /* actually used, non-NULL entries */
58058 duk_uint32_t new_e_size_minimum;
58059 duk_uint32_t new_e_size;
58060 duk_uint32_t new_a_size;
58061 duk_uint32_t new_h_size;
58062
58063 DUK_ASSERT(thr != NULL);
58064 DUK_ASSERT(obj != NULL);
58065
58066 /* Duktape 0.11.0 and prior tried to optimize the resize by not
58067 * counting the number of actually used keys prior to the resize.
58068 * This worked mostly well but also caused weird leak-like behavior
58069 * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count
58070 * the keys explicitly to compute the new entry part size.
58071 */
58072
58073 old_e_used = duk__count_used_e_keys(thr, obj);
58074 new_e_size_minimum = old_e_used + 1;
58075 new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
58076#if defined(DUK_USE_HOBJECT_HASH_PART)
58077 new_h_size = duk__get_default_h_size(new_e_size);
58078#else
58079 new_h_size = 0;
58080#endif
58081 new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
58082
58083#if defined(DUK_USE_OBJSIZES16)
58084 if (new_e_size > DUK_UINT16_MAX) {
58085 new_e_size = DUK_UINT16_MAX;
58086 }
58087 if (new_h_size > DUK_UINT16_MAX) {
58088 new_h_size = DUK_UINT16_MAX;
58089 }
58090 if (new_a_size > DUK_UINT16_MAX) {
58091 new_a_size = DUK_UINT16_MAX;
58092 }
58093#endif
58094 DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size);
58095
58096 if (!(new_e_size >= new_e_size_minimum)) {
58097 DUK_ERROR_ALLOC_FAILED(thr);
58098 DUK_WO_NORETURN(return;);
58099 }
58100
58101 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
58102}
58103
58104/* Grow array part for a new highest array index. */
58105DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
58106 duk_uint32_t new_e_size;
58107 duk_uint32_t new_a_size;
58108 duk_uint32_t new_a_size_minimum;
58109 duk_uint32_t new_h_size;
58110
58111 DUK_ASSERT(thr != NULL);
58112 DUK_ASSERT(obj != NULL);
58113 DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
58114
58115 new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
58116 new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
58117 new_a_size_minimum = highest_arr_idx + 1;
58118 new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
58119 DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
58120
58121#if defined(DUK_USE_OBJSIZES16)
58122 if (new_e_size > DUK_UINT16_MAX) {
58123 new_e_size = DUK_UINT16_MAX;
58124 }
58125 if (new_h_size > DUK_UINT16_MAX) {
58126 new_h_size = DUK_UINT16_MAX;
58127 }
58128 if (new_a_size > DUK_UINT16_MAX) {
58129 new_a_size = DUK_UINT16_MAX;
58130 }
58131#endif
58132
58133 if (!(new_a_size >= new_a_size_minimum)) {
58134 DUK_ERROR_ALLOC_FAILED(thr);
58135 DUK_WO_NORETURN(return;);
58136 }
58137
58138 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
58139}
58140
58141/* Abandon array part, moving array entries into entries part.
58142 * This requires a props resize, which is a heavy operation.
58143 * We also compact the entries part while we're at it, although
58144 * this is not strictly required.
58145 */
58146DUK_LOCAL void duk__abandon_array_part(duk_hthread *thr, duk_hobject *obj) {
58147 duk_uint32_t new_e_size_minimum;
58148 duk_uint32_t new_e_size;
58149 duk_uint32_t new_a_size;
58150 duk_uint32_t new_h_size;
58151 duk_uint32_t e_used; /* actually used, non-NULL keys */
58152 duk_uint32_t a_used;
58153 duk_uint32_t a_size;
58154
58155 DUK_ASSERT(thr != NULL);
58156 DUK_ASSERT(obj != NULL);
58157
58158 e_used = duk__count_used_e_keys(thr, obj);
58159 duk__compute_a_stats(thr, obj, &a_used, &a_size);
58160
58161 /*
58162 * Must guarantee all actually used array entries will fit into
58163 * new entry part. Add one growth step to ensure we don't run out
58164 * of space right away.
58165 */
58166
58167 new_e_size_minimum = e_used + a_used;
58168 new_e_size = new_e_size_minimum + duk__get_min_grow_e(new_e_size_minimum);
58169 new_a_size = 0;
58170#if defined(DUK_USE_HOBJECT_HASH_PART)
58171 new_h_size = duk__get_default_h_size(new_e_size);
58172#else
58173 new_h_size = 0;
58174#endif
58175
58176#if defined(DUK_USE_OBJSIZES16)
58177 if (new_e_size > DUK_UINT16_MAX) {
58178 new_e_size = DUK_UINT16_MAX;
58179 }
58180 if (new_h_size > DUK_UINT16_MAX) {
58181 new_h_size = DUK_UINT16_MAX;
58182 }
58183 if (new_a_size > DUK_UINT16_MAX) {
58184 new_a_size = DUK_UINT16_MAX;
58185 }
58186#endif
58187
58188 if (!(new_e_size >= new_e_size_minimum)) {
58189 DUK_ERROR_ALLOC_FAILED(thr);
58190 DUK_WO_NORETURN(return;);
58191 }
58192
58193 DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
58194 "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
58195 "resize to e_size=%ld, a_size=%ld, h_size=%ld",
58196 (void *) obj, (long) e_used, (long) a_used, (long) a_size,
58197 (long) new_e_size, (long) new_a_size, (long) new_h_size));
58198
58199 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
58200}
58201
58202/*
58203 * Compact an object. Minimizes allocation size for objects which are
58204 * not likely to be extended. This is useful for internal and non-
58205 * extensible objects, but can also be called for non-extensible objects.
58206 * May abandon the array part if it is computed to be too sparse.
58207 *
58208 * This call is relatively expensive, as it needs to scan both the
58209 * entries and the array part.
58210 *
58211 * The call may fail due to allocation error.
58212 */
58213
58214DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
58215 duk_uint32_t e_size; /* currently used -> new size */
58216 duk_uint32_t a_size; /* currently required */
58217 duk_uint32_t a_used; /* actually used */
58218 duk_uint32_t h_size;
58219 duk_bool_t abandon_array;
58220
58221 DUK_ASSERT(thr != NULL);
58222 DUK_ASSERT(obj != NULL);
58223
58224#if defined(DUK_USE_ROM_OBJECTS)
58225 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
58226 DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
58227 return;
58228 }
58229#endif
58230
58231 e_size = duk__count_used_e_keys(thr, obj);
58232 duk__compute_a_stats(thr, obj, &a_used, &a_size);
58233
58234 DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
58235 "resized array density would be: %ld/%ld = %lf",
58236 (long) e_size, (long) a_used, (long) a_size,
58237 (long) a_used, (long) a_size,
58238 (double) a_used / (double) a_size));
58239
58240 if (duk__abandon_array_density_check(a_used, a_size)) {
58241 DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
58242 (long) a_used, (long) a_size));
58243 abandon_array = 1;
58244 e_size += a_used;
58245 a_size = 0;
58246 } else {
58247 DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
58248 abandon_array = 0;
58249 }
58250
58251#if defined(DUK_USE_HOBJECT_HASH_PART)
58252 if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
58253 h_size = duk__get_default_h_size(e_size);
58254 } else {
58255 h_size = 0;
58256 }
58257#else
58258 h_size = 0;
58259#endif
58260
58261 DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
58262 (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
58263
58264 duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
58265}
58266
58267/*
58268 * Find an existing key from entry part either by linear scan or by
58269 * using the hash index (if it exists).
58270 *
58271 * Sets entry index (and possibly the hash index) to output variables,
58272 * which allows the caller to update the entry and hash entries in-place.
58273 * If entry is not found, both values are set to -1. If entry is found
58274 * but there is no hash part, h_idx is set to -1.
58275 */
58276
58277DUK_INTERNAL duk_bool_t duk_hobject_find_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
58278 DUK_ASSERT(obj != NULL);
58279 DUK_ASSERT(key != NULL);
58280 DUK_ASSERT(e_idx != NULL);
58281 DUK_ASSERT(h_idx != NULL);
58282 DUK_UNREF(heap);
58283
58284 if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
58285 {
58286 /* Linear scan: more likely because most objects are small.
58287 * This is an important fast path.
58288 *
58289 * XXX: this might be worth inlining for property lookups.
58290 */
58291 duk_uint_fast32_t i;
58292 duk_uint_fast32_t n;
58293 duk_hstring **h_keys_base;
58294 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_entry() using linear scan for lookup"));
58295
58296 h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
58297 n = DUK_HOBJECT_GET_ENEXT(obj);
58298 for (i = 0; i < n; i++) {
58299 if (h_keys_base[i] == key) {
58300 *e_idx = (duk_int_t) i;
58301 *h_idx = -1;
58302 return 1;
58303 }
58304 }
58305 }
58306#if defined(DUK_USE_HOBJECT_HASH_PART)
58307 else
58308 {
58309 /* hash lookup */
58310 duk_uint32_t n;
58311 duk_uint32_t i, step;
58312 duk_uint32_t *h_base;
58313 duk_uint32_t mask;
58314
58315 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_entry() using hash part for lookup"));
58316
58317 h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
58318 n = DUK_HOBJECT_GET_HSIZE(obj);
58319 mask = n - 1;
58320 i = DUK_HSTRING_GET_HASH(key) & mask;
58321 step = 1; /* Cache friendly but clustering prone. */
58322
58323 for (;;) {
58324 duk_uint32_t t;
58325
58326 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
58327 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
58328 t = h_base[i];
58329 DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
58330 (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */
58331
58332 if (t == DUK__HASH_UNUSED) {
58333 break;
58334 } else if (t == DUK__HASH_DELETED) {
58335 DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
58336 (long) i, (long) t));
58337 } else {
58338 DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
58339 if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
58340 DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
58341 (long) i, (long) t, (void *) key));
58342 *e_idx = (duk_int_t) t;
58343 *h_idx = (duk_int_t) i;
58344 return 1;
58345 }
58346 DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
58347 (long) i, (long) t));
58348 }
58349 i = (i + step) & mask;
58350
58351 /* Guaranteed to finish (hash is larger than #props). */
58352 }
58353 }
58354#endif /* DUK_USE_HOBJECT_HASH_PART */
58355
58356 /* Not found, leave e_idx and h_idx unset. */
58357 return 0;
58358}
58359
58360/* For internal use: get non-accessor entry value */
58361DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
58362 duk_int_t e_idx;
58363 duk_int_t h_idx;
58364
58365 DUK_ASSERT(obj != NULL);
58366 DUK_ASSERT(key != NULL);
58367 DUK_UNREF(heap);
58368
58369 if (duk_hobject_find_entry(heap, obj, key, &e_idx, &h_idx)) {
58370 DUK_ASSERT(e_idx >= 0);
58371 if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
58372 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
58373 }
58374 }
58375 return NULL;
58376}
58377
58378DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx) {
58379 return duk_hobject_find_entry_tval_ptr(heap, obj, DUK_HEAP_GET_STRING(heap, stridx));
58380}
58381
58382/* For internal use: get non-accessor entry value and attributes */
58383DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) {
58384 duk_int_t e_idx;
58385 duk_int_t h_idx;
58386
58387 DUK_ASSERT(obj != NULL);
58388 DUK_ASSERT(key != NULL);
58389 DUK_ASSERT(out_attrs != NULL);
58390 DUK_UNREF(heap);
58391
58392 if (duk_hobject_find_entry(heap, obj, key, &e_idx, &h_idx)) {
58393 DUK_ASSERT(e_idx >= 0);
58394 if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
58395 *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
58396 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
58397 }
58398 }
58399 /* If not found, out_attrs is left unset. */
58400 return NULL;
58401}
58402
58403/* For internal use: get array part value */
58404DUK_INTERNAL duk_tval *duk_hobject_find_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
58405 duk_tval *tv;
58406
58407 DUK_ASSERT(obj != NULL);
58408 DUK_UNREF(heap);
58409
58410 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
58411 return NULL;
58412 }
58413 if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
58414 return NULL;
58415 }
58416 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
58417 return tv;
58418}
58419
58420/*
58421 * Allocate and initialize a new entry, resizing the properties allocation
58422 * if necessary. Returns entry index (e_idx) or throws an error if alloc fails.
58423 *
58424 * Sets the key of the entry (increasing the key's refcount), and updates
58425 * the hash part if it exists. Caller must set value and flags, and update
58426 * the entry value refcount. A decref for the previous value is not necessary.
58427 */
58428
58429DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
58430 duk_uint32_t idx;
58431
58432 DUK_ASSERT(thr != NULL);
58433 DUK_ASSERT(obj != NULL);
58434 DUK_ASSERT(key != NULL);
58435 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
58436
58437#if defined(DUK_USE_ASSERTIONS)
58438 /* key must not already exist in entry part */
58439 {
58440 duk_uint_fast32_t i;
58441 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
58442 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
58443 }
58444 }
58445#endif
58446
58447 if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
58448 /* only need to guarantee 1 more slot, but allocation growth is in chunks */
58449 DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
58450 duk__grow_props_for_new_entry_item(thr, obj);
58451 }
58452 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
58453 idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
58454
58455 /* previous value is assumed to be garbage, so don't touch it */
58456 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
58457 DUK_HSTRING_INCREF(thr, key);
58458
58459#if defined(DUK_USE_HOBJECT_HASH_PART)
58460 if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
58461 duk_uint32_t n, mask;
58462 duk_uint32_t i, step;
58463 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
58464
58465 n = DUK_HOBJECT_GET_HSIZE(obj);
58466 mask = n - 1;
58467 i = DUK_HSTRING_GET_HASH(key) & mask;
58468 step = 1; /* Cache friendly but clustering prone. */
58469
58470 for (;;) {
58471 duk_uint32_t t = h_base[i];
58472 if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
58473 DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld",
58474 (long) i, (long) idx));
58475 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
58476 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
58477 DUK_ASSERT_DISABLE(idx >= 0);
58478 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
58479 h_base[i] = idx;
58480 break;
58481 }
58482 DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld", (long) i));
58483 i = (i + step) & mask;
58484
58485 /* Guaranteed to finish (hash is larger than #props). */
58486 }
58487 }
58488#endif /* DUK_USE_HOBJECT_HASH_PART */
58489
58490 /* Note: we could return the hash index here too, but it's not
58491 * needed right now.
58492 */
58493
58494 DUK_ASSERT_DISABLE(idx >= 0);
58495 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
58496 DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
58497 return (duk_int_t) idx;
58498}
58499
58500/*
58501 * Object internal value
58502 *
58503 * Returned value is guaranteed to be reachable / incref'd, caller does not need
58504 * to incref OR decref. No proxies or accessors are invoked, no prototype walk.
58505 */
58506
58507DUK_INTERNAL duk_tval *duk_hobject_get_internal_value_tval_ptr(duk_heap *heap, duk_hobject *obj) {
58508 return duk_hobject_find_entry_tval_ptr_stridx(heap, obj, DUK_STRIDX_INT_VALUE);
58509}
58510
58511DUK_LOCAL duk_heaphdr *duk_hobject_get_internal_value_heaphdr(duk_heap *heap, duk_hobject *obj) {
58512 duk_tval *tv;
58513
58514 DUK_ASSERT(heap != NULL);
58515 DUK_ASSERT(obj != NULL);
58516
58517 tv = duk_hobject_get_internal_value_tval_ptr(heap, obj);
58518 if (tv != NULL) {
58519 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
58520 DUK_ASSERT(h != NULL);
58521 return h;
58522 }
58523
58524 return NULL;
58525}
58526
58527DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
58528 duk_hstring *h;
58529
58530 h = (duk_hstring *) duk_hobject_get_internal_value_heaphdr(heap, obj);
58531 if (h != NULL) {
58532 DUK_ASSERT(DUK_HEAPHDR_IS_STRING((duk_heaphdr *) h));
58533 }
58534 return h;
58535}
58536
58537DUK_LOCAL duk_hobject *duk__hobject_get_entry_object_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx) {
58538 duk_tval *tv;
58539 duk_hobject *h;
58540
58541 tv = duk_hobject_find_entry_tval_ptr_stridx(heap, obj, stridx);
58542 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
58543 h = DUK_TVAL_GET_OBJECT(tv);
58544 DUK_ASSERT(h != NULL);
58545 return h;
58546 }
58547 return NULL;
58548}
58549
58550DUK_INTERNAL duk_harray *duk_hobject_get_formals(duk_hthread *thr, duk_hobject *obj) {
58551 duk_harray *h;
58552
58553 h = (duk_harray *) duk__hobject_get_entry_object_stridx(thr->heap, obj, DUK_STRIDX_INT_FORMALS);
58554 if (h != NULL) {
58555 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
58556 DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
58557 }
58558 return h;
58559}
58560
58561DUK_INTERNAL duk_hobject *duk_hobject_get_varmap(duk_hthread *thr, duk_hobject *obj) {
58562 duk_hobject *h;
58563
58564 h = duk__hobject_get_entry_object_stridx(thr->heap, obj, DUK_STRIDX_INT_VARMAP);
58565 return h;
58566}
58567
58568/*
58569 * Arguments handling helpers (argument map mainly).
58570 *
58571 * An arguments object has exotic behavior for some numeric indices.
58572 * Accesses may translate to identifier operations which may have
58573 * arbitrary side effects (potentially invalidating any duk_tval
58574 * pointers).
58575 */
58576
58577/* Lookup 'key' from arguments internal 'map', perform a variable lookup
58578 * if mapped, and leave the result on top of stack (and return non-zero).
58579 * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
58580 */
58581DUK_LOCAL
58582duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
58583 duk_hobject *obj,
58584 duk_hstring *key,
58585 duk_propdesc *temp_desc,
58586 duk_hobject **out_map,
58587 duk_hobject **out_varenv) {
58588 duk_hobject *map;
58589 duk_hobject *varenv;
58590 duk_bool_t rc;
58591
58592 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58593
58594 DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
58595 "(obj -> %!O, key -> %!O)",
58596 (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
58597 (duk_heaphdr *) obj, (duk_heaphdr *) key));
58598
58599 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
58600 DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
58601 return 0;
58602 }
58603
58604 map = duk_require_hobject(thr, -1);
58605 DUK_ASSERT(map != NULL);
58606 duk_pop_unsafe(thr); /* map is reachable through obj */
58607
58608 if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
58609 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
58610 return 0;
58611 }
58612
58613 /* [... varname] */
58614 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
58615 (duk_tval *) duk_get_tval(thr, -1)));
58616 DUK_ASSERT(duk_is_string(thr, -1)); /* guaranteed when building arguments */
58617
58618 /* get varenv for varname (callee's declarative lexical environment) */
58619 rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
58620 DUK_UNREF(rc);
58621 DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
58622 varenv = duk_require_hobject(thr, -1);
58623 DUK_ASSERT(varenv != NULL);
58624 duk_pop_unsafe(thr); /* varenv remains reachable through 'obj' */
58625
58626 DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
58627
58628 /* success: leave varname in stack */
58629 *out_map = map;
58630 *out_varenv = varenv;
58631 return 1; /* [... varname] */
58632}
58633
58634/* Lookup 'key' from arguments internal 'map', and leave replacement value
58635 * on stack top if mapped (and return non-zero).
58636 * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
58637 */
58638DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
58639 duk_hobject *map;
58640 duk_hobject *varenv;
58641 duk_hstring *varname;
58642
58643 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58644
58645 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
58646 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
58647 return 0;
58648 }
58649
58650 /* [... varname] */
58651
58652 varname = duk_require_hstring(thr, -1);
58653 DUK_ASSERT(varname != NULL);
58654 duk_pop_unsafe(thr); /* varname is still reachable */
58655
58656 DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
58657 "key=%!O, varname=%!O",
58658 (duk_heaphdr *) key,
58659 (duk_heaphdr *) varname));
58660
58661 (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
58662
58663 /* [... value this_binding] */
58664
58665 duk_pop_unsafe(thr);
58666
58667 /* leave result on stack top */
58668 return 1;
58669}
58670
58671/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
58672 * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
58673 * Assumes stack top contains 'put' value (which is NOT popped).
58674 */
58675DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) {
58676 duk_hobject *map;
58677 duk_hobject *varenv;
58678 duk_hstring *varname;
58679
58680 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58681
58682 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
58683 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
58684 return;
58685 }
58686
58687 /* [... put_value varname] */
58688
58689 varname = duk_require_hstring(thr, -1);
58690 DUK_ASSERT(varname != NULL);
58691 duk_pop_unsafe(thr); /* varname is still reachable */
58692
58693 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
58694 "key=%!O, varname=%!O, value=%!T",
58695 (duk_heaphdr *) key,
58696 (duk_heaphdr *) varname,
58697 (duk_tval *) duk_require_tval(thr, -1)));
58698
58699 /* [... put_value] */
58700
58701 /*
58702 * Note: although arguments object variable mappings are only established
58703 * for non-strict functions (and a call to a non-strict function created
58704 * the arguments object in question), an inner strict function may be doing
58705 * the actual property write. Hence the throw_flag applied here comes from
58706 * the property write call.
58707 */
58708
58709 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag);
58710
58711 /* [... put_value] */
58712}
58713
58714/* Lookup 'key' from arguments internal 'map', delete mapping if found.
58715 * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the
58716 * variable/argument itself (where the map points) is not deleted.
58717 */
58718DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
58719 duk_hobject *map;
58720
58721 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58722
58723 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
58724 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
58725 return;
58726 }
58727
58728 map = duk_require_hobject(thr, -1);
58729 DUK_ASSERT(map != NULL);
58730 duk_pop_unsafe(thr); /* map is reachable through obj */
58731
58732 DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
58733 (duk_heaphdr *) key));
58734
58735 /* Note: no recursion issue, we can trust 'map' to behave */
58736 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
58737 DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
58738 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
58739 DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
58740}
58741
58742/*
58743 * ECMAScript compliant [[GetOwnProperty]](P), for internal use only.
58744 *
58745 * If property is found:
58746 * - Fills descriptor fields to 'out_desc'
58747 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
58748 * property onto the stack ('undefined' for accessor properties).
58749 * - Returns non-zero
58750 *
58751 * If property is not found:
58752 * - 'out_desc' is left in untouched state (possibly garbage)
58753 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
58754 * set)
58755 * - Returns zero
58756 *
58757 * Notes:
58758 *
58759 * - Getting a property descriptor may cause an allocation (and hence
58760 * GC) to take place, hence reachability and refcount of all related
58761 * values matter. Reallocation of value stack, properties, etc may
58762 * invalidate many duk_tval pointers (concretely, those which reside
58763 * in memory areas subject to reallocation). However, heap object
58764 * pointers are never affected (heap objects have stable pointers).
58765 *
58766 * - The value of a plain property is always reachable and has a non-zero
58767 * reference count.
58768 *
58769 * - The value of a virtual property is not necessarily reachable from
58770 * elsewhere and may have a refcount of zero. Hence we push it onto
58771 * the valstack for the caller, which ensures it remains reachable
58772 * while it is needed.
58773 *
58774 * - There are no virtual accessor properties. Hence, all getters and
58775 * setters are always related to concretely stored properties, which
58776 * ensures that the get/set functions in the resulting descriptor are
58777 * reachable and have non-zero refcounts. Should there be virtual
58778 * accessor properties later, this would need to change.
58779 */
58780
58781DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) {
58782 duk_tval *tv;
58783
58784 DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
58785 "arr_idx=%ld (obj -> %!O, key -> %!O)",
58786 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
58787 (long) flags, (long) arr_idx,
58788 (duk_heaphdr *) obj, (duk_heaphdr *) key));
58789
58790 DUK_ASSERT(thr != NULL);
58791 DUK_ASSERT(thr->heap != NULL);
58792 DUK_ASSERT(obj != NULL);
58793 DUK_ASSERT(key != NULL);
58794 DUK_ASSERT(out_desc != NULL);
58795 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58796
58797 DUK_STATS_INC(thr->heap, stats_getownpropdesc_count);
58798
58799 /* Each code path returning 1 (= found) must fill in all the output
58800 * descriptor fields. We don't do it beforehand because it'd be
58801 * unnecessary work if the property isn't found and would happen
58802 * multiple times for an inheritance chain.
58803 */
58804 DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc));
58805#if 0
58806 out_desc->flags = 0;
58807 out_desc->get = NULL;
58808 out_desc->set = NULL;
58809 out_desc->e_idx = -1;
58810 out_desc->h_idx = -1;
58811 out_desc->a_idx = -1;
58812#endif
58813
58814 /*
58815 * Try entries part first because it's the common case.
58816 *
58817 * Array part lookups are usually handled by the array fast path, and
58818 * are not usually inherited. Array and entry parts never contain the
58819 * same keys so the entry part vs. array part order doesn't matter.
58820 */
58821
58822 if (duk_hobject_find_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) {
58823 duk_int_t e_idx = out_desc->e_idx;
58824 DUK_ASSERT(out_desc->e_idx >= 0);
58825 out_desc->a_idx = -1;
58826 out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
58827 out_desc->get = NULL;
58828 out_desc->set = NULL;
58829 if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) {
58830 DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
58831 out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
58832 out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
58833 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58834 /* a dummy undefined value is pushed to make valstack
58835 * behavior uniform for caller
58836 */
58837 duk_push_undefined(thr);
58838 }
58839 } else {
58840 DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
58841 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
58842 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58843 duk_push_tval(thr, tv);
58844 }
58845 }
58846 goto prop_found;
58847 }
58848
58849 /*
58850 * Try array part.
58851 */
58852
58853 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
58854 if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
58855 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
58856 if (!DUK_TVAL_IS_UNUSED(tv)) {
58857 DUK_DDD(DUK_DDDPRINT("-> found in array part"));
58858 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58859 duk_push_tval(thr, tv);
58860 }
58861 /* implicit attributes */
58862 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
58863 DUK_PROPDESC_FLAG_CONFIGURABLE |
58864 DUK_PROPDESC_FLAG_ENUMERABLE;
58865 out_desc->get = NULL;
58866 out_desc->set = NULL;
58867 out_desc->e_idx = -1;
58868 out_desc->h_idx = -1;
58869 out_desc->a_idx = (duk_int_t) arr_idx; /* XXX: limit 2G due to being signed */
58870 goto prop_found;
58871 }
58872 }
58873 }
58874
58875 DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property"));
58876
58877 /*
58878 * Not found as a concrete property, check for virtual properties.
58879 */
58880
58881 if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) {
58882 /* Quick skip. */
58883 goto prop_not_found;
58884 }
58885
58886 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
58887 duk_harray *a;
58888
58889 DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld",
58890 (duk_heaphdr *) key, (long) arr_idx));
58891
58892 a = (duk_harray *) obj;
58893 DUK_HARRAY_ASSERT_VALID(a);
58894
58895 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
58896 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
58897
58898 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58899 duk_push_uint(thr, (duk_uint_t) a->length);
58900 }
58901 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
58902 if (DUK_HARRAY_LENGTH_WRITABLE(a)) {
58903 out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
58904 }
58905 out_desc->get = NULL;
58906 out_desc->set = NULL;
58907 out_desc->e_idx = -1;
58908 out_desc->h_idx = -1;
58909 out_desc->a_idx = -1;
58910
58911 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
58912 goto prop_found_noexotic; /* cannot be arguments exotic */
58913 }
58914 } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
58915 DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
58916 (duk_heaphdr *) key, (long) arr_idx));
58917
58918 /* XXX: charlen; avoid multiple lookups? */
58919
58920 if (arr_idx != DUK__NO_ARRAY_INDEX) {
58921 duk_hstring *h_val;
58922
58923 DUK_DDD(DUK_DDDPRINT("array index exists"));
58924
58925 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
58926 DUK_ASSERT(h_val);
58927 if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
58928 DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
58929 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58930 duk_push_hstring(thr, h_val);
58931 duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
58932 }
58933 out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
58934 DUK_PROPDESC_FLAG_VIRTUAL;
58935 out_desc->get = NULL;
58936 out_desc->set = NULL;
58937 out_desc->e_idx = -1;
58938 out_desc->h_idx = -1;
58939 out_desc->a_idx = -1;
58940
58941 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
58942 goto prop_found_noexotic; /* cannot be arguments exotic */
58943 } else {
58944 /* index is above internal string length -> property is fully normal */
58945 DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
58946 }
58947 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
58948 duk_hstring *h_val;
58949
58950 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
58951
58952 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
58953 DUK_ASSERT(h_val != NULL);
58954 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58955 duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
58956 }
58957 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
58958 out_desc->get = NULL;
58959 out_desc->set = NULL;
58960 out_desc->e_idx = -1;
58961 out_desc->h_idx = -1;
58962 out_desc->a_idx = -1;
58963
58964 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
58965 goto prop_found_noexotic; /* cannot be arguments exotic */
58966 }
58967 }
58968#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
58969 else if (DUK_HOBJECT_IS_BUFOBJ(obj)) {
58970 duk_hbufobj *h_bufobj;
58971 duk_uint_t byte_off;
58972 duk_small_uint_t elem_size;
58973
58974 h_bufobj = (duk_hbufobj *) obj;
58975 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
58976 DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld",
58977 (duk_heaphdr *) key, (long) arr_idx));
58978
58979 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
58980 DUK_DDD(DUK_DDDPRINT("array index exists"));
58981
58982 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
58983 * length downshift won't.
58984 */
58985 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
58986 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
58987 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
58988 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
58989 duk_uint8_t *data;
58990
58991 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
58992 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
58993 duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
58994 } else {
58995 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
58996 duk_push_uint(thr, 0);
58997 }
58998 }
58999 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
59000 DUK_PROPDESC_FLAG_VIRTUAL;
59001 if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
59002 /* ArrayBuffer indices are non-standard and are
59003 * non-enumerable to avoid their serialization.
59004 */
59005 out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
59006 }
59007 out_desc->get = NULL;
59008 out_desc->set = NULL;
59009 out_desc->e_idx = -1;
59010 out_desc->h_idx = -1;
59011 out_desc->a_idx = -1;
59012
59013 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
59014 goto prop_found_noexotic; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
59015 } else {
59016 /* index is above internal buffer length -> property is fully normal */
59017 DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
59018 }
59019 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
59020 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
59021
59022 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
59023 /* Length in elements: take into account shift, but
59024 * intentionally don't check the underlying buffer here.
59025 */
59026 duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift);
59027 }
59028 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
59029 out_desc->get = NULL;
59030 out_desc->set = NULL;
59031 out_desc->e_idx = -1;
59032 out_desc->h_idx = -1;
59033 out_desc->a_idx = -1;
59034
59035 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
59036 goto prop_found_noexotic; /* cannot be arguments exotic */
59037 }
59038 }
59039#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
59040
59041 /* Array properties have exotic behavior but they are concrete,
59042 * so no special handling here.
59043 *
59044 * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
59045 * is only relevant as a post-check implemented below; hence no
59046 * check here.
59047 */
59048
59049 /*
59050 * Not found as concrete or virtual.
59051 */
59052
59053 prop_not_found:
59054 DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
59055 DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss);
59056 return 0;
59057
59058 /*
59059 * Found.
59060 *
59061 * Arguments object has exotic post-processing, see E5 Section 10.6,
59062 * description of [[GetOwnProperty]] variant for arguments.
59063 */
59064
59065 prop_found:
59066 DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
59067
59068 /* Notes:
59069 * - Only numbered indices are relevant, so arr_idx fast reject is good
59070 * (this is valid unless there are more than 4**32-1 arguments).
59071 * - Since variable lookup has no side effects, this can be skipped if
59072 * DUK_GETDESC_FLAG_PUSH_VALUE is not set.
59073 */
59074
59075 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
59076 arr_idx != DUK__NO_ARRAY_INDEX &&
59077 (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) {
59078 duk_propdesc temp_desc;
59079
59080 /* Magically bound variable cannot be an accessor. However,
59081 * there may be an accessor property (or a plain property) in
59082 * place with magic behavior removed. This happens e.g. when
59083 * a magic property is redefined with defineProperty().
59084 * Cannot assert for "not accessor" here.
59085 */
59086
59087 /* replaces top of stack with new value if necessary */
59088 DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
59089
59090 /* This can perform a variable lookup but only into a declarative
59091 * environment which has no side effects.
59092 */
59093 if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
59094 DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
59095 (duk_tval *) duk_get_tval(thr, -2),
59096 (duk_tval *) duk_get_tval(thr, -1)));
59097 /* [... old_result result] -> [... result] */
59098 duk_remove_m2(thr);
59099 }
59100 }
59101
59102 prop_found_noexotic:
59103 DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit);
59104 return 1;
59105}
59106
59107DUK_INTERNAL 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) {
59108 DUK_ASSERT(thr != NULL);
59109 DUK_ASSERT(obj != NULL);
59110 DUK_ASSERT(key != NULL);
59111 DUK_ASSERT(out_desc != NULL);
59112 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59113
59114 return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
59115}
59116
59117/*
59118 * ECMAScript compliant [[GetProperty]](P), for internal use only.
59119 *
59120 * If property is found:
59121 * - Fills descriptor fields to 'out_desc'
59122 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
59123 * property onto the stack ('undefined' for accessor properties).
59124 * - Returns non-zero
59125 *
59126 * If property is not found:
59127 * - 'out_desc' is left in untouched state (possibly garbage)
59128 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
59129 * set)
59130 * - Returns zero
59131 *
59132 * May cause arbitrary side effects and invalidate (most) duk_tval
59133 * pointers.
59134 */
59135
59136DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) {
59137 duk_hobject *curr;
59138 duk_uint32_t arr_idx;
59139 duk_uint_t sanity;
59140
59141 DUK_ASSERT(thr != NULL);
59142 DUK_ASSERT(thr->heap != NULL);
59143 DUK_ASSERT(obj != NULL);
59144 DUK_ASSERT(key != NULL);
59145 DUK_ASSERT(out_desc != NULL);
59146 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59147
59148 DUK_STATS_INC(thr->heap, stats_getpropdesc_count);
59149
59150 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
59151
59152 DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
59153 "arr_idx=%ld (obj -> %!O, key -> %!O)",
59154 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
59155 (long) flags, (long) arr_idx,
59156 (duk_heaphdr *) obj, (duk_heaphdr *) key));
59157
59158 curr = obj;
59159 DUK_ASSERT(curr != NULL);
59160 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
59161 do {
59162 if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
59163 /* stack contains value (if requested), 'out_desc' is set */
59164 DUK_STATS_INC(thr->heap, stats_getpropdesc_hit);
59165 return 1;
59166 }
59167
59168 /* not found in 'curr', next in prototype chain; impose max depth */
59169 if (DUK_UNLIKELY(sanity-- == 0)) {
59170 if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
59171 /* treat like property not found */
59172 break;
59173 } else {
59174 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
59175 DUK_WO_NORETURN(return 0;);
59176 }
59177 }
59178 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
59179 } while (curr != NULL);
59180
59181 /* out_desc is left untouched (possibly garbage), caller must use return
59182 * value to determine whether out_desc can be looked up
59183 */
59184
59185 DUK_STATS_INC(thr->heap, stats_getpropdesc_miss);
59186 return 0;
59187}
59188
59189/*
59190 * Shallow fast path checks for accessing array elements with numeric
59191 * indices. The goal is to try to avoid coercing an array index to an
59192 * (interned) string for the most common lookups, in particular, for
59193 * standard Array objects.
59194 *
59195 * Interning is avoided but only for a very narrow set of cases:
59196 * - Object has array part, index is within array allocation, and
59197 * value is not unused (= key exists)
59198 * - Object has no interfering exotic behavior (e.g. arguments or
59199 * string object exotic behaviors interfere, array exotic
59200 * behavior does not).
59201 *
59202 * Current shortcoming: if key does not exist (even if it is within
59203 * the array allocation range) a slow path lookup with interning is
59204 * always required. This can probably be fixed so that there is a
59205 * quick fast path for non-existent elements as well, at least for
59206 * standard Array objects.
59207 */
59208
59209#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
59210DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
59211 duk_tval *tv;
59212 duk_uint32_t idx;
59213
59214 DUK_UNREF(thr);
59215
59216 if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
59217 !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
59218 !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
59219 !DUK_HOBJECT_IS_BUFOBJ(obj) &&
59220 !DUK_HOBJECT_IS_PROXY(obj))) {
59221 /* Must have array part and no conflicting exotic behaviors.
59222 * Doesn't need to have array special behavior, e.g. Arguments
59223 * object has array part.
59224 */
59225 return NULL;
59226 }
59227
59228 /* Arrays never have other exotic behaviors. */
59229
59230 DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
59231 "behavior, object has array part)"));
59232
59233#if defined(DUK_USE_FASTINT)
59234 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59235 idx = duk__tval_fastint_to_arr_idx(tv_key);
59236 } else
59237#endif
59238 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
59239 idx = duk__tval_number_to_arr_idx(tv_key);
59240 } else {
59241 DUK_DDD(DUK_DDDPRINT("key is not a number"));
59242 return NULL;
59243 }
59244
59245 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
59246 * is 0xffffffffUL. We don't need to check for that explicitly
59247 * because 0xffffffffUL will never be inside object 'a_size'.
59248 */
59249
59250 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
59251 DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
59252 return NULL;
59253 }
59254 DUK_ASSERT(idx != 0xffffffffUL);
59255 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
59256
59257 /* XXX: for array instances we could take a shortcut here and assume
59258 * Array.prototype doesn't contain an array index property.
59259 */
59260
59261 DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
59262 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
59263 if (!DUK_TVAL_IS_UNUSED(tv)) {
59264 DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
59265 return tv;
59266 }
59267
59268 DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
59269 return NULL;
59270}
59271
59272DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
59273 duk_tval *tv;
59274 duk_harray *a;
59275 duk_uint32_t idx;
59276 duk_uint32_t old_len, new_len;
59277
59278 if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
59279 DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
59280 DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
59281 return 0;
59282 }
59283 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
59284
59285 a = (duk_harray *) obj;
59286 DUK_HARRAY_ASSERT_VALID(a);
59287
59288#if defined(DUK_USE_FASTINT)
59289 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59290 idx = duk__tval_fastint_to_arr_idx(tv_key);
59291 } else
59292#endif
59293 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
59294 idx = duk__tval_number_to_arr_idx(tv_key);
59295 } else {
59296 DUK_DDD(DUK_DDDPRINT("key is not a number"));
59297 return 0;
59298 }
59299
59300 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
59301 * is 0xffffffffUL. We don't need to check for that explicitly
59302 * because 0xffffffffUL will never be inside object 'a_size'.
59303 */
59304
59305 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */
59306 return 0;
59307 }
59308 DUK_ASSERT(idx != 0xffffffffUL);
59309 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
59310
59311 old_len = a->length;
59312
59313 if (idx >= old_len) {
59314 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
59315 "(arr_idx=%ld, old_len=%ld)",
59316 (long) idx, (long) old_len));
59317 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
59318 /* The correct behavior here is either a silent error
59319 * or a TypeError, depending on strictness. Fall back
59320 * to the slow path to handle the situation.
59321 */
59322 return 0;
59323 }
59324 new_len = idx + 1;
59325
59326 ((duk_harray *) obj)->length = new_len;
59327 }
59328
59329 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
59330 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
59331
59332 DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
59333 return 1;
59334}
59335#endif /* DUK_USE_ARRAY_PROP_FASTPATH */
59336
59337/*
59338 * Fast path for bufobj getprop/putprop
59339 */
59340
59341#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
59342DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
59343 duk_uint32_t idx;
59344 duk_hbufobj *h_bufobj;
59345 duk_uint_t byte_off;
59346 duk_small_uint_t elem_size;
59347 duk_uint8_t *data;
59348
59349 if (!DUK_HOBJECT_IS_BUFOBJ(obj)) {
59350 return 0;
59351 }
59352 h_bufobj = (duk_hbufobj *) obj;
59353 if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
59354 return 0;
59355 }
59356
59357#if defined(DUK_USE_FASTINT)
59358 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59359 idx = duk__tval_fastint_to_arr_idx(tv_key);
59360 } else
59361#endif
59362 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
59363 idx = duk__tval_number_to_arr_idx(tv_key);
59364 } else {
59365 return 0;
59366 }
59367
59368 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
59369 * is 0xffffffffUL. We don't need to check for that explicitly
59370 * because 0xffffffffUL will never be inside bufobj length.
59371 */
59372
59373 /* Careful with wrapping (left shifting idx would be unsafe). */
59374 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
59375 return 0;
59376 }
59377 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
59378
59379 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
59380 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
59381
59382 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
59383 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
59384 duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
59385 } else {
59386 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
59387 duk_push_uint(thr, 0);
59388 }
59389
59390 return 1;
59391}
59392#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
59393
59394#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
59395DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
59396 duk_uint32_t idx;
59397 duk_hbufobj *h_bufobj;
59398 duk_uint_t byte_off;
59399 duk_small_uint_t elem_size;
59400 duk_uint8_t *data;
59401
59402 if (!(DUK_HOBJECT_IS_BUFOBJ(obj) &&
59403 DUK_TVAL_IS_NUMBER(tv_val))) {
59404 return 0;
59405 }
59406 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufobjs now */
59407
59408 h_bufobj = (duk_hbufobj *) obj;
59409 if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
59410 return 0;
59411 }
59412
59413#if defined(DUK_USE_FASTINT)
59414 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59415 idx = duk__tval_fastint_to_arr_idx(tv_key);
59416 } else
59417#endif
59418 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
59419 idx = duk__tval_number_to_arr_idx(tv_key);
59420 } else {
59421 return 0;
59422 }
59423
59424 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
59425 * is 0xffffffffUL. We don't need to check for that explicitly
59426 * because 0xffffffffUL will never be inside bufobj length.
59427 */
59428
59429 /* Careful with wrapping (left shifting idx would be unsafe). */
59430 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
59431 return 0;
59432 }
59433 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
59434
59435 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
59436 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
59437
59438 /* Value is required to be a number in the fast path so there
59439 * are no side effects in write coercion.
59440 */
59441 duk_push_tval(thr, tv_val);
59442 DUK_ASSERT(duk_is_number(thr, -1));
59443
59444 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
59445 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
59446 duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
59447 } else {
59448 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
59449 }
59450
59451 duk_pop_unsafe(thr);
59452 return 1;
59453}
59454#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
59455
59456/*
59457 * GETPROP: ECMAScript property read.
59458 */
59459
59460DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
59461 duk_tval tv_obj_copy;
59462 duk_tval tv_key_copy;
59463 duk_hobject *curr = NULL;
59464 duk_hstring *key = NULL;
59465 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
59466 duk_propdesc desc;
59467 duk_uint_t sanity;
59468
59469 DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
59470 (void *) thr, (void *) tv_obj, (void *) tv_key,
59471 (duk_tval *) tv_obj, (duk_tval *) tv_key));
59472
59473 DUK_ASSERT(thr != NULL);
59474 DUK_ASSERT(thr->heap != NULL);
59475 DUK_ASSERT(tv_obj != NULL);
59476 DUK_ASSERT(tv_key != NULL);
59477
59478 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59479
59480 DUK_STATS_INC(thr->heap, stats_getprop_all);
59481
59482 /*
59483 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
59484 * them being invalidated by a valstack resize.
59485 *
59486 * XXX: this is now an overkill for many fast paths. Rework this
59487 * to be faster (although switching to a valstack discipline might
59488 * be a better solution overall).
59489 */
59490
59491 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
59492 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
59493 tv_obj = &tv_obj_copy;
59494 tv_key = &tv_key_copy;
59495
59496 /*
59497 * Coercion and fast path processing
59498 */
59499
59500 switch (DUK_TVAL_GET_TAG(tv_obj)) {
59501 case DUK_TAG_UNDEFINED:
59502 case DUK_TAG_NULL: {
59503 /* Note: unconditional throw */
59504 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
59505#if defined(DUK_USE_PARANOID_ERRORS)
59506 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
59507#else
59508 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
59509 duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
59510#endif
59511 DUK_WO_NORETURN(return 0;);
59512 break;
59513 }
59514
59515 case DUK_TAG_BOOLEAN: {
59516 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
59517 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
59518 break;
59519 }
59520
59521 case DUK_TAG_STRING: {
59522 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
59523 duk_int_t pop_count;
59524
59525 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
59526 /* Symbols (ES2015 or hidden) don't have virtual properties. */
59527 DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype"));
59528 curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
59529 break;
59530 }
59531
59532#if defined(DUK_USE_FASTINT)
59533 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59534 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
59535 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
59536 pop_count = 0;
59537 } else
59538#endif
59539 if (DUK_TVAL_IS_NUMBER(tv_key)) {
59540 arr_idx = duk__tval_number_to_arr_idx(tv_key);
59541 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
59542 pop_count = 0;
59543 } else {
59544 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59545 DUK_ASSERT(key != NULL);
59546 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
59547 "coercion key is %!T, arr_idx %ld",
59548 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
59549 pop_count = 1;
59550 }
59551
59552 if (arr_idx != DUK__NO_ARRAY_INDEX &&
59553 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
59554 duk_pop_n_unsafe(thr, pop_count);
59555 duk_push_hstring(thr, h);
59556 duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
59557
59558 DUK_STATS_INC(thr->heap, stats_getprop_stringidx);
59559 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
59560 "after coercion -> return char)",
59561 (duk_tval *) duk_get_tval(thr, -1)));
59562 return 1;
59563 }
59564
59565 if (pop_count == 0) {
59566 /* This is a pretty awkward control flow, but we need to recheck the
59567 * key coercion here.
59568 */
59569 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59570 DUK_ASSERT(key != NULL);
59571 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
59572 "coercion key is %!T, arr_idx %ld",
59573 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
59574 }
59575
59576 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
59577 duk_pop_unsafe(thr); /* [key] -> [] */
59578 duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
59579
59580 DUK_STATS_INC(thr->heap, stats_getprop_stringlen);
59581 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
59582 "return string length)",
59583 (duk_tval *) duk_get_tval(thr, -1)));
59584 return 1;
59585 }
59586
59587 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
59588 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
59589 goto lookup; /* avoid double coercion */
59590 }
59591
59592 case DUK_TAG_OBJECT: {
59593#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
59594 duk_tval *tmp;
59595#endif
59596
59597 curr = DUK_TVAL_GET_OBJECT(tv_obj);
59598 DUK_ASSERT(curr != NULL);
59599
59600 /* XXX: array .length fast path (important in e.g. loops)? */
59601
59602#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
59603 tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
59604 if (tmp) {
59605 duk_push_tval(thr, tmp);
59606
59607 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
59608 "fast path)",
59609 (duk_tval *) duk_get_tval(thr, -1)));
59610 DUK_STATS_INC(thr->heap, stats_getprop_arrayidx);
59611 return 1;
59612 }
59613#endif
59614
59615#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
59616 if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
59617 /* Read value pushed on stack. */
59618 DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj "
59619 "fast path)",
59620 (duk_tval *) duk_get_tval(thr, -1)));
59621 DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx);
59622 return 1;
59623 }
59624#endif
59625
59626#if defined(DUK_USE_ES6_PROXY)
59627 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) {
59628 duk_hobject *h_target;
59629
59630 if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
59631 /* -> [ ... trap handler ] */
59632 DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
59633 DUK_STATS_INC(thr->heap, stats_getprop_proxy);
59634 duk_push_hobject(thr, h_target); /* target */
59635 duk_push_tval(thr, tv_key); /* P */
59636 duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
59637 duk_call_method(thr, 3 /*nargs*/);
59638
59639 /* Target object must be checked for a conflicting
59640 * non-configurable property.
59641 */
59642 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59643 DUK_ASSERT(key != NULL);
59644
59645 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
59646 duk_tval *tv_hook = duk_require_tval(thr, -3); /* value from hook */
59647 duk_tval *tv_targ = duk_require_tval(thr, -1); /* value from target */
59648 duk_bool_t datadesc_reject;
59649 duk_bool_t accdesc_reject;
59650
59651 DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
59652 "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
59653 "desc.get=%p, desc.set=%p",
59654 (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
59655 (unsigned long) desc.flags,
59656 (void *) desc.get, (void *) desc.set));
59657
59658 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
59659 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
59660 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
59661 !duk_js_samevalue(tv_hook, tv_targ);
59662 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
59663 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
59664 (desc.get == NULL) &&
59665 !DUK_TVAL_IS_UNDEFINED(tv_hook);
59666 if (datadesc_reject || accdesc_reject) {
59667 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
59668 DUK_WO_NORETURN(return 0;);
59669 }
59670
59671 duk_pop_2_unsafe(thr);
59672 } else {
59673 duk_pop_unsafe(thr);
59674 }
59675 return 1; /* return value */
59676 }
59677
59678 curr = h_target; /* resume lookup from target */
59679 DUK_TVAL_SET_OBJECT(tv_obj, curr);
59680 }
59681#endif /* DUK_USE_ES6_PROXY */
59682
59683 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
59684 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59685 DUK_ASSERT(key != NULL);
59686
59687 DUK_STATS_INC(thr->heap, stats_getprop_arguments);
59688 if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
59689 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
59690 "key matches magically bound property -> skip standard "
59691 "Get with replacement value)",
59692 (duk_tval *) duk_get_tval(thr, -1)));
59693
59694 /* no need for 'caller' post-check, because 'key' must be an array index */
59695
59696 duk_remove_m2(thr); /* [key result] -> [result] */
59697 return 1;
59698 }
59699
59700 goto lookup; /* avoid double coercion */
59701 }
59702 break;
59703 }
59704
59705 /* Buffer has virtual properties similar to string, but indexed values
59706 * are numbers, not 1-byte buffers/strings which would perform badly.
59707 */
59708 case DUK_TAG_BUFFER: {
59709 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
59710 duk_int_t pop_count;
59711
59712 /*
59713 * Because buffer values are often looped over, a number fast path
59714 * is important.
59715 */
59716
59717#if defined(DUK_USE_FASTINT)
59718 if (DUK_TVAL_IS_FASTINT(tv_key)) {
59719 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
59720 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
59721 pop_count = 0;
59722 }
59723 else
59724#endif
59725 if (DUK_TVAL_IS_NUMBER(tv_key)) {
59726 arr_idx = duk__tval_number_to_arr_idx(tv_key);
59727 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
59728 pop_count = 0;
59729 } else {
59730 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59731 DUK_ASSERT(key != NULL);
59732 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
59733 "coercion key is %!T, arr_idx %ld",
59734 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
59735 pop_count = 1;
59736 }
59737
59738 if (arr_idx != DUK__NO_ARRAY_INDEX &&
59739 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
59740 duk_pop_n_unsafe(thr, pop_count);
59741 duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
59742 DUK_STATS_INC(thr->heap, stats_getprop_bufferidx);
59743 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
59744 "after coercion -> return byte as number)",
59745 (duk_tval *) duk_get_tval(thr, -1)));
59746 return 1;
59747 }
59748
59749 if (pop_count == 0) {
59750 /* This is a pretty awkward control flow, but we need to recheck the
59751 * key coercion here.
59752 */
59753 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59754 DUK_ASSERT(key != NULL);
59755 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
59756 "coercion key is %!T, arr_idx %ld",
59757 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
59758 }
59759
59760 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
59761 duk_pop_unsafe(thr); /* [key] -> [] */
59762 duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
59763 DUK_STATS_INC(thr->heap, stats_getprop_bufferlen);
59764
59765 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' "
59766 "after coercion -> return buffer length)",
59767 (duk_tval *) duk_get_tval(thr, -1)));
59768 return 1;
59769 }
59770
59771 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
59772 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
59773 goto lookup; /* avoid double coercion */
59774 }
59775
59776 case DUK_TAG_POINTER: {
59777 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
59778 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
59779 break;
59780 }
59781
59782 case DUK_TAG_LIGHTFUNC: {
59783 /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */
59784 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
59785 curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
59786 break;
59787 }
59788
59789#if defined(DUK_USE_FASTINT)
59790 case DUK_TAG_FASTINT:
59791#endif
59792 default: {
59793 /* number */
59794 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
59795 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
59796 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
59797 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
59798 break;
59799 }
59800 }
59801
59802 /* key coercion (unless already coerced above) */
59803 DUK_ASSERT(key == NULL);
59804 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59805 DUK_ASSERT(key != NULL);
59806 /*
59807 * Property lookup
59808 */
59809
59810 lookup:
59811 /* [key] (coerced) */
59812 DUK_ASSERT(curr != NULL);
59813 DUK_ASSERT(key != NULL);
59814
59815 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
59816 do {
59817 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
59818 goto next_in_chain;
59819 }
59820
59821 if (desc.get != NULL) {
59822 /* accessor with defined getter */
59823 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
59824
59825 duk_pop_unsafe(thr); /* [key undefined] -> [key] */
59826 duk_push_hobject(thr, desc.get);
59827 duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
59828#if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT)
59829 duk_dup_m3(thr);
59830 duk_call_method(thr, 1); /* [key getter this key] -> [key retval] */
59831#else
59832 duk_call_method(thr, 0); /* [key getter this] -> [key retval] */
59833#endif
59834 } else {
59835 /* [key value] or [key undefined] */
59836
59837 /* data property or accessor without getter */
59838 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
59839 (desc.get == NULL));
59840
59841 /* if accessor without getter, return value is undefined */
59842 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
59843 duk_is_undefined(thr, -1));
59844
59845 /* Note: for an accessor without getter, falling through to
59846 * check for "caller" exotic behavior is unnecessary as
59847 * "undefined" will never activate the behavior. But it does
59848 * no harm, so we'll do it anyway.
59849 */
59850 }
59851
59852 goto found; /* [key result] */
59853
59854 next_in_chain:
59855 /* XXX: option to pretend property doesn't exist if sanity limit is
59856 * hit might be useful.
59857 */
59858 if (DUK_UNLIKELY(sanity-- == 0)) {
59859 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
59860 DUK_WO_NORETURN(return 0;);
59861 }
59862 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
59863 } while (curr != NULL);
59864
59865 /*
59866 * Not found
59867 */
59868
59869 duk_to_undefined(thr, -1); /* [key] -> [undefined] (default value) */
59870
59871 DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(thr, -1)));
59872 return 0;
59873
59874 /*
59875 * Found; post-processing (Function and arguments objects)
59876 */
59877
59878 found:
59879 /* [key result] */
59880
59881#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
59882 /* Special behavior for 'caller' property of (non-bound) function objects
59883 * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
59884 * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
59885 * Quite interestingly, a non-strict function with no formal arguments
59886 * will get an arguments object -without- special 'caller' behavior!
59887 *
59888 * The E5.1 spec is a bit ambiguous if this special behavior applies when
59889 * a bound function is the base value (not the 'caller' value): Section
59890 * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
59891 * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
59892 * However, Section 13.3.5.4 has "NOTE: Function objects created using
59893 * Function.prototype.bind use the default [[Get]] internal method."
59894 * The current implementation assumes this means that bound functions
59895 * should not have the special [[Get]] behavior.
59896 *
59897 * The E5.1 spec is also a bit unclear if the TypeError throwing is
59898 * applied if the 'caller' value is a strict bound function. The
59899 * current implementation will throw even for both strict non-bound
59900 * and strict bound functions.
59901 *
59902 * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
59903 * tests.
59904 *
59905 * This exotic behavior is disabled when the non-standard 'caller' property
59906 * is enabled, as it conflicts with the free use of 'caller'.
59907 */
59908 if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
59909 DUK_TVAL_IS_OBJECT(tv_obj)) {
59910 duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
59911 DUK_ASSERT(orig != NULL);
59912
59913 if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
59914 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
59915 duk_hobject *h;
59916
59917 /* XXX: The TypeError is currently not applied to bound
59918 * functions because the 'strict' flag is not copied by
59919 * bind(). This may or may not be correct, the specification
59920 * only refers to the value being a "strict mode Function
59921 * object" which is ambiguous.
59922 */
59923 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig));
59924
59925 h = duk_get_hobject(thr, -1); /* NULL if not an object */
59926 if (h &&
59927 DUK_HOBJECT_IS_FUNCTION(h) &&
59928 DUK_HOBJECT_HAS_STRICT(h)) {
59929 /* XXX: sufficient to check 'strict', assert for 'is function' */
59930 DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
59931 DUK_WO_NORETURN(return 0;);
59932 }
59933 }
59934 }
59935#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
59936
59937 duk_remove_m2(thr); /* [key result] -> [result] */
59938
59939 DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(thr, -1)));
59940 return 1;
59941}
59942
59943/*
59944 * HASPROP: ECMAScript property existence check ("in" operator).
59945 *
59946 * Interestingly, the 'in' operator does not do any coercion of
59947 * the target object.
59948 */
59949
59950DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
59951 duk_tval tv_key_copy;
59952 duk_hobject *obj;
59953 duk_hstring *key;
59954 duk_uint32_t arr_idx;
59955 duk_bool_t rc;
59956 duk_propdesc desc;
59957
59958 DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
59959 (void *) thr, (void *) tv_obj, (void *) tv_key,
59960 (duk_tval *) tv_obj, (duk_tval *) tv_key));
59961
59962 DUK_ASSERT(thr != NULL);
59963 DUK_ASSERT(thr->heap != NULL);
59964 DUK_ASSERT(tv_obj != NULL);
59965 DUK_ASSERT(tv_key != NULL);
59966 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59967
59968 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
59969 tv_key = &tv_key_copy;
59970
59971 /*
59972 * The 'in' operator requires an object as its right hand side,
59973 * throwing a TypeError unconditionally if this is not the case.
59974 *
59975 * However, lightfuncs need to behave like fully fledged objects
59976 * here to be maximally transparent, so we need to handle them
59977 * here. Same goes for plain buffers which behave like ArrayBuffers.
59978 */
59979
59980 /* XXX: Refactor key coercion so that it's only called once. It can't
59981 * be trivially lifted here because the object must be type checked
59982 * first.
59983 */
59984
59985 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
59986 obj = DUK_TVAL_GET_OBJECT(tv_obj);
59987 DUK_ASSERT(obj != NULL);
59988
59989 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59990 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
59991 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59992 if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) {
59993 rc = 1;
59994 goto pop_and_return;
59995 }
59996 obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
59997 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
59998 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
59999
60000 /* If not found, resume existence check from %NativeFunctionPrototype%.
60001 * We can just substitute the value in this case; nothing will
60002 * need the original base value (as would be the case with e.g.
60003 * setters/getters.
60004 */
60005 obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
60006 } else {
60007 /* Note: unconditional throw */
60008 DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
60009 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
60010 DUK_WO_NORETURN(return 0;);
60011 }
60012
60013 /* XXX: fast path for arrays? */
60014
60015 DUK_ASSERT(key != NULL);
60016 DUK_ASSERT(obj != NULL);
60017 DUK_UNREF(arr_idx);
60018
60019#if defined(DUK_USE_ES6_PROXY)
60020 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
60021 duk_hobject *h_target;
60022 duk_bool_t tmp_bool;
60023
60024 /* XXX: the key in 'key in obj' is string coerced before we're called
60025 * (which is the required behavior in E5/E5.1/E6) so the key is a string
60026 * here already.
60027 */
60028
60029 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
60030 /* [ ... key trap handler ] */
60031 DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
60032 duk_push_hobject(thr, h_target); /* target */
60033 duk_push_tval(thr, tv_key); /* P */
60034 duk_call_method(thr, 2 /*nargs*/);
60035 tmp_bool = duk_to_boolean_top_pop(thr);
60036 if (!tmp_bool) {
60037 /* Target object must be checked for a conflicting
60038 * non-configurable property.
60039 */
60040
60041 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
60042 DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
60043 "conflicting property; desc.flags=0x%08lx, "
60044 "desc.get=%p, desc.set=%p",
60045 (duk_heaphdr *) key, (unsigned long) desc.flags,
60046 (void *) desc.get, (void *) desc.set));
60047 /* XXX: Extensibility check for target uses IsExtensible(). If we
60048 * implemented the isExtensible trap and didn't reject proxies as
60049 * proxy targets, it should be respected here.
60050 */
60051 if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
60052 DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
60053 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
60054 DUK_WO_NORETURN(return 0;);
60055 }
60056 }
60057 }
60058
60059 duk_pop_unsafe(thr); /* [ key ] -> [] */
60060 return tmp_bool;
60061 }
60062
60063 obj = h_target; /* resume check from proxy target */
60064 }
60065#endif /* DUK_USE_ES6_PROXY */
60066
60067 /* XXX: inline into a prototype walking loop? */
60068
60069 rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */
60070 /* fall through */
60071
60072 pop_and_return:
60073 duk_pop_unsafe(thr); /* [ key ] -> [] */
60074 return rc;
60075}
60076
60077/*
60078 * HASPROP variant used internally.
60079 *
60080 * This primitive must never throw an error, callers rely on this.
60081 * In particular, don't throw an error for prototype loops; instead,
60082 * pretend like the property doesn't exist if a prototype sanity limit
60083 * is reached.
60084 *
60085 * Does not implement proxy behavior: if applied to a proxy object,
60086 * returns key existence on the proxy object itself.
60087 */
60088
60089DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
60090 duk_propdesc dummy;
60091
60092 DUK_ASSERT(thr != NULL);
60093 DUK_ASSERT(thr->heap != NULL);
60094 DUK_ASSERT(obj != NULL);
60095 DUK_ASSERT(key != NULL);
60096
60097 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
60098
60099 return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */
60100}
60101
60102/*
60103 * Helper: handle Array object 'length' write which automatically
60104 * deletes properties, see E5 Section 15.4.5.1, step 3. This is
60105 * quite tricky to get right.
60106 *
60107 * Used by duk_hobject_putprop().
60108 */
60109
60110/* Coerce a new .length candidate to a number and check that it's a valid
60111 * .length.
60112 */
60113DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) {
60114 duk_uint32_t res;
60115 duk_double_t d;
60116
60117#if !defined(DUK_USE_PREFER_SIZE)
60118#if defined(DUK_USE_FASTINT)
60119 /* When fastints are enabled, the most interesting case is assigning
60120 * a fastint to .length (e.g. arr.length = 0).
60121 */
60122 if (DUK_TVAL_IS_FASTINT(tv)) {
60123 /* Very common case. */
60124 duk_int64_t fi;
60125 fi = DUK_TVAL_GET_FASTINT(tv);
60126 if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) {
60127 goto fail_range;
60128 }
60129 return (duk_uint32_t) fi;
60130 }
60131#else /* DUK_USE_FASTINT */
60132 /* When fastints are not enabled, the most interesting case is any
60133 * number.
60134 */
60135 if (DUK_TVAL_IS_DOUBLE(tv)) {
60136 d = DUK_TVAL_GET_NUMBER(tv);
60137 }
60138#endif /* DUK_USE_FASTINT */
60139 else
60140#endif /* !DUK_USE_PREFER_SIZE */
60141 {
60142 /* In all other cases, and when doing a size optimized build,
60143 * fall back to the comprehensive handler.
60144 */
60145 d = duk_js_tonumber(thr, tv);
60146 }
60147
60148 /* Refuse to update an Array's 'length' to a value outside the
60149 * 32-bit range. Negative zero is accepted as zero.
60150 */
60151 res = duk_double_to_uint32_t(d);
60152 if (!duk_double_equals((duk_double_t) res, d)) {
60153 goto fail_range;
60154 }
60155
60156 return res;
60157
60158 fail_range:
60159 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
60160 DUK_WO_NORETURN(return 0;);
60161}
60162
60163/* Delete elements required by a smaller length, taking into account
60164 * potentially non-configurable elements. Returns non-zero if all
60165 * elements could be deleted, and zero if all or some elements could
60166 * not be deleted. Also writes final "target length" to 'out_result_len'.
60167 * This is the length value that should go into the 'length' property
60168 * (must be set by the caller). Never throws an error.
60169 */
60170DUK_LOCAL
60171duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
60172 duk_hobject *obj,
60173 duk_uint32_t old_len,
60174 duk_uint32_t new_len,
60175 duk_bool_t force_flag,
60176 duk_uint32_t *out_result_len) {
60177 duk_uint32_t target_len;
60178 duk_uint_fast32_t i;
60179 duk_uint32_t arr_idx;
60180 duk_hstring *key;
60181 duk_tval *tv;
60182 duk_bool_t rc;
60183
60184 DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
60185 "probably need to remove elements",
60186 (long) old_len, (long) new_len));
60187
60188 /*
60189 * New length is smaller than old length, need to delete properties above
60190 * the new length.
60191 *
60192 * If array part exists, this is straightforward: array entries cannot
60193 * be non-configurable so this is guaranteed to work.
60194 *
60195 * If array part does not exist, array-indexed values are scattered
60196 * in the entry part, and some may not be configurable (preventing length
60197 * from becoming lower than their index + 1). To handle the algorithm
60198 * in E5 Section 15.4.5.1, step l correctly, we scan the entire property
60199 * set twice.
60200 */
60201
60202 DUK_ASSERT(thr != NULL);
60203 DUK_ASSERT(obj != NULL);
60204 DUK_ASSERT(new_len < old_len);
60205 DUK_ASSERT(out_result_len != NULL);
60206 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
60207
60208 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
60209 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
60210
60211 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
60212 /*
60213 * All defined array-indexed properties are in the array part
60214 * (we assume the array part is comprehensive), and all array
60215 * entries are writable, configurable, and enumerable. Thus,
60216 * nothing can prevent array entries from being deleted.
60217 */
60218
60219 DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
60220
60221 if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
60222 /* XXX: assertion that entries >= old_len are already unused */
60223 i = old_len;
60224 } else {
60225 i = DUK_HOBJECT_GET_ASIZE(obj);
60226 }
60227 DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
60228
60229 while (i > new_len) {
60230 i--;
60231 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
60232 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
60233 }
60234
60235 *out_result_len = new_len;
60236 return 1;
60237 } else {
60238 /*
60239 * Entries part is a bit more complex.
60240 */
60241
60242 /* Stage 1: find highest preventing non-configurable entry (if any).
60243 * When forcing, ignore non-configurability.
60244 */
60245
60246 DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
60247
60248 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
60249 "(highest preventing non-configurable entry (if any))"));
60250
60251 target_len = new_len;
60252 if (force_flag) {
60253 DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
60254 goto skip_stage1;
60255 }
60256 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
60257 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
60258 if (!key) {
60259 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
60260 continue;
60261 }
60262 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
60263 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
60264 continue;
60265 }
60266
60267 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
60268 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
60269 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
60270 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
60271
60272 if (arr_idx < new_len) {
60273 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
60274 (long) i, (long) arr_idx));
60275 continue;
60276 }
60277 if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
60278 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
60279 (long) i, (long) arr_idx));
60280 continue;
60281 }
60282
60283 /* relevant array index is non-configurable, blocks write */
60284 if (arr_idx >= target_len) {
60285 DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
60286 "update target_len %ld -> %ld",
60287 (long) i, (long) arr_idx, (long) target_len,
60288 (long) (arr_idx + 1)));
60289 target_len = arr_idx + 1;
60290 }
60291 }
60292 skip_stage1:
60293
60294 /* stage 2: delete configurable entries above target length */
60295
60296 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
60297 (long) old_len, (long) new_len, (long) target_len));
60298
60299 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
60300 "entries >= target_len"));
60301
60302 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
60303 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
60304 if (!key) {
60305 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
60306 continue;
60307 }
60308 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
60309 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
60310 continue;
60311 }
60312
60313 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
60314 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
60315 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
60316 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
60317
60318 if (arr_idx < target_len) {
60319 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
60320 (long) i, (long) arr_idx));
60321 continue;
60322 }
60323 DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */
60324
60325 DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
60326 (long) i, (long) arr_idx));
60327
60328 /*
60329 * Slow delete, but we don't care as we're already in a very slow path.
60330 * The delete always succeeds: key has no exotic behavior, property
60331 * is configurable, and no resize occurs.
60332 */
60333 rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
60334 DUK_UNREF(rc);
60335 DUK_ASSERT(rc != 0);
60336 }
60337
60338 /* stage 3: update length (done by caller), decide return code */
60339
60340 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
60341
60342 *out_result_len = target_len;
60343
60344 if (target_len == new_len) {
60345 DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
60346 return 1;
60347 }
60348 DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
60349 "full length adjustment), return error"));
60350 return 0;
60351 }
60352
60353 DUK_UNREACHABLE();
60354}
60355
60356/* XXX: is valstack top best place for argument? */
60357DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
60358 duk_harray *a;
60359 duk_uint32_t old_len;
60360 duk_uint32_t new_len;
60361 duk_uint32_t result_len;
60362 duk_bool_t rc;
60363
60364 DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
60365 "new val: %!T",
60366 (duk_tval *) duk_get_tval(thr, -1)));
60367
60368 DUK_ASSERT(thr != NULL);
60369 DUK_ASSERT(obj != NULL);
60370
60371 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
60372
60373 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
60374 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
60375 a = (duk_harray *) obj;
60376 DUK_HARRAY_ASSERT_VALID(a);
60377
60378 DUK_ASSERT(duk_is_valid_index(thr, -1));
60379
60380 /*
60381 * Get old and new length
60382 */
60383
60384 old_len = a->length;
60385 new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
60386 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
60387
60388 /*
60389 * Writability check
60390 */
60391
60392 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
60393 DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
60394 return 0;
60395 }
60396
60397 /*
60398 * New length not lower than old length => no changes needed
60399 * (not even array allocation).
60400 */
60401
60402 if (new_len >= old_len) {
60403 DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions"));
60404 a->length = new_len;
60405 return 1;
60406 }
60407
60408 DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
60409
60410 /*
60411 * New length lower than old length => delete elements, then
60412 * update length.
60413 *
60414 * Note: even though a bunch of elements have been deleted, the 'desc' is
60415 * still valid as properties haven't been resized (and entries compacted).
60416 */
60417
60418 rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
60419 DUK_ASSERT(result_len >= new_len && result_len <= old_len);
60420
60421 a->length = result_len;
60422
60423 /* XXX: shrink array allocation or entries compaction here? */
60424
60425 return rc;
60426}
60427
60428/*
60429 * PUTPROP: ECMAScript property write.
60430 *
60431 * Unlike ECMAScript primitive which returns nothing, returns 1 to indicate
60432 * success and 0 to indicate failure (assuming throw is not set).
60433 *
60434 * This is an extremely tricky function. Some examples:
60435 *
60436 * * Currently a decref may trigger a GC, which may compact an object's
60437 * property allocation. Consequently, any entry indices (e_idx) will
60438 * be potentially invalidated by a decref.
60439 *
60440 * * Exotic behaviors (strings, arrays, arguments object) require,
60441 * among other things:
60442 *
60443 * - Preprocessing before and postprocessing after an actual property
60444 * write. For example, array index write requires pre-checking the
60445 * array 'length' property for access control, and may require an
60446 * array 'length' update after the actual write has succeeded (but
60447 * not if it fails).
60448 *
60449 * - Deletion of multiple entries, as a result of array 'length' write.
60450 *
60451 * * Input values are taken as pointers which may point to the valstack.
60452 * If valstack is resized because of the put (this may happen at least
60453 * when the array part is abandoned), the pointers can be invalidated.
60454 * (We currently make a copy of all of the input values to avoid issues.)
60455 */
60456
60457DUK_INTERNAL 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) {
60458 duk_tval tv_obj_copy;
60459 duk_tval tv_key_copy;
60460 duk_tval tv_val_copy;
60461 duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */
60462 duk_hobject *curr;
60463 duk_hstring *key = NULL;
60464 duk_propdesc desc;
60465 duk_tval *tv;
60466 duk_uint32_t arr_idx;
60467 duk_bool_t rc;
60468 duk_int_t e_idx;
60469 duk_uint_t sanity;
60470 duk_uint32_t new_array_length = 0; /* 0 = no update */
60471
60472 DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
60473 "(obj -> %!T, key -> %!T, val -> %!T)",
60474 (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
60475 (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
60476
60477 DUK_ASSERT(thr != NULL);
60478 DUK_ASSERT(thr->heap != NULL);
60479 DUK_ASSERT(tv_obj != NULL);
60480 DUK_ASSERT(tv_key != NULL);
60481 DUK_ASSERT(tv_val != NULL);
60482
60483 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
60484
60485 DUK_STATS_INC(thr->heap, stats_putprop_all);
60486
60487 /*
60488 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
60489 * them being invalidated by a valstack resize.
60490 *
60491 * XXX: this is an overkill for some paths, so optimize this later
60492 * (or maybe switch to a stack arguments model entirely).
60493 */
60494
60495 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
60496 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
60497 DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
60498 tv_obj = &tv_obj_copy;
60499 tv_key = &tv_key_copy;
60500 tv_val = &tv_val_copy;
60501
60502 /*
60503 * Coercion and fast path processing.
60504 */
60505
60506 switch (DUK_TVAL_GET_TAG(tv_obj)) {
60507 case DUK_TAG_UNDEFINED:
60508 case DUK_TAG_NULL: {
60509 /* Note: unconditional throw */
60510 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
60511 (duk_tval *) tv_obj));
60512#if defined(DUK_USE_PARANOID_ERRORS)
60513 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
60514#else
60515 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
60516 duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
60517#endif
60518 DUK_WO_NORETURN(return 0;);
60519 break;
60520 }
60521
60522 case DUK_TAG_BOOLEAN: {
60523 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
60524 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
60525 break;
60526 }
60527
60528 case DUK_TAG_STRING: {
60529 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
60530
60531 /*
60532 * Note: currently no fast path for array index writes.
60533 * They won't be possible anyway as strings are immutable.
60534 */
60535
60536 DUK_ASSERT(key == NULL);
60537 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
60538 DUK_ASSERT(key != NULL);
60539
60540 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
60541 /* Symbols (ES2015 or hidden) don't have virtual properties. */
60542 curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
60543 goto lookup;
60544 }
60545
60546 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
60547 goto fail_not_writable;
60548 }
60549
60550 if (arr_idx != DUK__NO_ARRAY_INDEX &&
60551 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
60552 goto fail_not_writable;
60553 }
60554
60555 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
60556 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
60557 goto lookup; /* avoid double coercion */
60558 }
60559
60560 case DUK_TAG_OBJECT: {
60561 orig = DUK_TVAL_GET_OBJECT(tv_obj);
60562 DUK_ASSERT(orig != NULL);
60563
60564#if defined(DUK_USE_ROM_OBJECTS)
60565 /* With this check in place fast paths won't need read-only
60566 * object checks. This is technically incorrect if there are
60567 * setters that cause no writes to ROM objects, but current
60568 * built-ins don't have such setters.
60569 */
60570 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
60571 DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
60572 goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */
60573 }
60574#endif
60575
60576 /* The fast path for array property put is not fully compliant:
60577 * If one places conflicting number-indexed properties into
60578 * Array.prototype (for example, a non-writable Array.prototype[7])
60579 * the fast path will incorrectly ignore them.
60580 *
60581 * This fast path could be made compliant by falling through
60582 * to the slow path if the previous value was UNUSED. This would
60583 * also remove the need to check for extensibility. Right now a
60584 * non-extensible array is slower than an extensible one as far
60585 * as writes are concerned.
60586 *
60587 * The fast path behavior is documented in more detail here:
60588 * tests/ecmascript/test-misc-array-fast-write.js
60589 */
60590
60591 /* XXX: array .length? */
60592
60593#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
60594 if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) {
60595 DUK_DDD(DUK_DDDPRINT("array fast path success"));
60596 DUK_STATS_INC(thr->heap, stats_putprop_arrayidx);
60597 return 1;
60598 }
60599#endif
60600
60601#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
60602 if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
60603 DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path"));
60604 DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx);
60605 return 1;
60606 }
60607#endif
60608
60609#if defined(DUK_USE_ES6_PROXY)
60610 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) {
60611 duk_hobject *h_target;
60612 duk_bool_t tmp_bool;
60613
60614 if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
60615 /* -> [ ... trap handler ] */
60616 DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
60617 DUK_STATS_INC(thr->heap, stats_putprop_proxy);
60618 duk_push_hobject(thr, h_target); /* target */
60619 duk_push_tval(thr, tv_key); /* P */
60620 duk_push_tval(thr, tv_val); /* V */
60621 duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
60622 duk_call_method(thr, 4 /*nargs*/);
60623 tmp_bool = duk_to_boolean_top_pop(thr);
60624 if (!tmp_bool) {
60625 goto fail_proxy_rejected;
60626 }
60627
60628 /* Target object must be checked for a conflicting
60629 * non-configurable property.
60630 */
60631 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
60632 DUK_ASSERT(key != NULL);
60633
60634 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
60635 duk_tval *tv_targ = duk_require_tval(thr, -1);
60636 duk_bool_t datadesc_reject;
60637 duk_bool_t accdesc_reject;
60638
60639 DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
60640 "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
60641 "desc.get=%p, desc.set=%p",
60642 (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
60643 (unsigned long) desc.flags,
60644 (void *) desc.get, (void *) desc.set));
60645
60646 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
60647 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
60648 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
60649 !duk_js_samevalue(tv_val, tv_targ);
60650 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
60651 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
60652 (desc.set == NULL);
60653 if (datadesc_reject || accdesc_reject) {
60654 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
60655 DUK_WO_NORETURN(return 0;);
60656 }
60657
60658 duk_pop_2_unsafe(thr);
60659 } else {
60660 duk_pop_unsafe(thr);
60661 }
60662 return 1; /* success */
60663 }
60664
60665 orig = h_target; /* resume write to target */
60666 DUK_TVAL_SET_OBJECT(tv_obj, orig);
60667 }
60668#endif /* DUK_USE_ES6_PROXY */
60669
60670 curr = orig;
60671 break;
60672 }
60673
60674 case DUK_TAG_BUFFER: {
60675 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
60676 duk_int_t pop_count = 0;
60677
60678 /*
60679 * Because buffer values may be looped over and read/written
60680 * from, an array index fast path is important.
60681 */
60682
60683#if defined(DUK_USE_FASTINT)
60684 if (DUK_TVAL_IS_FASTINT(tv_key)) {
60685 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
60686 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
60687 pop_count = 0;
60688 } else
60689#endif
60690 if (DUK_TVAL_IS_NUMBER(tv_key)) {
60691 arr_idx = duk__tval_number_to_arr_idx(tv_key);
60692 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
60693 pop_count = 0;
60694 } else {
60695 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
60696 DUK_ASSERT(key != NULL);
60697 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
60698 "coercion key is %!T, arr_idx %ld",
60699 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
60700 pop_count = 1;
60701 }
60702
60703 if (arr_idx != DUK__NO_ARRAY_INDEX &&
60704 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
60705 duk_uint8_t *data;
60706 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
60707 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
60708
60709 /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
60710 * as input is within duk_int_t range (capped outside it).
60711 */
60712#if defined(DUK_USE_FASTINT)
60713 /* Buffer writes are often integers. */
60714 if (DUK_TVAL_IS_FASTINT(tv_val)) {
60715 data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
60716 }
60717 else
60718#endif
60719 {
60720 duk_push_tval(thr, tv_val);
60721 data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1);
60722 pop_count++;
60723 }
60724
60725 duk_pop_n_unsafe(thr, pop_count);
60726 DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
60727 DUK_STATS_INC(thr->heap, stats_putprop_bufferidx);
60728 return 1;
60729 }
60730
60731 if (pop_count == 0) {
60732 /* This is a pretty awkward control flow, but we need to recheck the
60733 * key coercion here.
60734 */
60735 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
60736 DUK_ASSERT(key != NULL);
60737 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
60738 "coercion key is %!T, arr_idx %ld",
60739 (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
60740 }
60741
60742 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
60743 goto fail_not_writable;
60744 }
60745
60746 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
60747 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
60748 goto lookup; /* avoid double coercion */
60749 }
60750
60751 case DUK_TAG_POINTER: {
60752 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
60753 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
60754 break;
60755 }
60756
60757 case DUK_TAG_LIGHTFUNC: {
60758 /* Lightfuncs have no own properties and are considered non-extensible.
60759 * However, the write may be captured by an inherited setter which
60760 * means we can't stop the lookup here.
60761 */
60762 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
60763 curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
60764 break;
60765 }
60766
60767#if defined(DUK_USE_FASTINT)
60768 case DUK_TAG_FASTINT:
60769#endif
60770 default: {
60771 /* number */
60772 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
60773 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
60774 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
60775 break;
60776 }
60777 }
60778
60779 DUK_ASSERT(key == NULL);
60780 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
60781 DUK_ASSERT(key != NULL);
60782
60783 lookup:
60784
60785 /*
60786 * Check whether the property already exists in the prototype chain.
60787 * Note that the actual write goes into the original base object
60788 * (except if an accessor property captures the write).
60789 */
60790
60791 /* [key] */
60792
60793 DUK_ASSERT(curr != NULL);
60794 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
60795 do {
60796 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
60797 goto next_in_chain;
60798 }
60799
60800 if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
60801 /*
60802 * Found existing accessor property (own or inherited).
60803 * Call setter with 'this' set to orig, and value as the only argument.
60804 * Setter calls are OK even for ROM objects.
60805 *
60806 * Note: no exotic arguments object behavior, because [[Put]] never
60807 * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
60808 */
60809
60810 duk_hobject *setter;
60811
60812 DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
60813
60814 setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
60815 if (!setter) {
60816 goto fail_no_setter;
60817 }
60818 duk_push_hobject(thr, setter);
60819 duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */
60820 duk_push_tval(thr, tv_val); /* [key setter this val] */
60821#if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT)
60822 duk_dup_m4(thr);
60823 duk_call_method(thr, 2); /* [key setter this val key] -> [key retval] */
60824#else
60825 duk_call_method(thr, 1); /* [key setter this val] -> [key retval] */
60826#endif
60827 duk_pop_unsafe(thr); /* ignore retval -> [key] */
60828 goto success_no_arguments_exotic;
60829 }
60830
60831 if (orig == NULL) {
60832 /*
60833 * Found existing own or inherited plain property, but original
60834 * base is a primitive value.
60835 */
60836 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
60837 goto fail_base_primitive;
60838 }
60839
60840 if (curr != orig) {
60841 /*
60842 * Found existing inherited plain property.
60843 * Do an access control check, and if OK, write
60844 * new property to 'orig'.
60845 */
60846 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
60847 DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
60848 goto fail_not_extensible;
60849 }
60850 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
60851 DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
60852 goto fail_not_writable;
60853 }
60854 DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
60855 goto create_new;
60856 } else {
60857 /*
60858 * Found existing own (non-inherited) plain property.
60859 * Do an access control check and update in place.
60860 */
60861
60862 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
60863 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
60864 goto fail_not_writable;
60865 }
60866 if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
60867 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
60868
60869 if (DUK_HOBJECT_IS_ARRAY(curr)) {
60870 /*
60871 * Write to 'length' of an array is a very complex case
60872 * handled in a helper which updates both the array elements
60873 * and writes the new 'length'. The write may result in an
60874 * unconditional RangeError or a partial write (indicated
60875 * by a return code).
60876 *
60877 * Note: the helper has an unnecessary writability check
60878 * for 'length', we already know it is writable.
60879 */
60880 DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr)); /* only virtual array property */
60881
60882 DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
60883
60884 /* XXX: the helper currently assumes stack top contains new
60885 * 'length' value and the whole calling convention is not very
60886 * compatible with what we need.
60887 */
60888
60889 duk_push_tval(thr, tv_val); /* [key val] */
60890 rc = duk__handle_put_array_length(thr, orig);
60891 duk_pop_unsafe(thr); /* [key val] -> [key] */
60892 if (!rc) {
60893 goto fail_array_length_partial;
60894 }
60895
60896 /* key is 'length', cannot match argument exotic behavior */
60897 goto success_no_arguments_exotic;
60898 }
60899#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
60900 else if (DUK_HOBJECT_IS_BUFOBJ(curr)) {
60901 duk_hbufobj *h_bufobj;
60902 duk_uint_t byte_off;
60903 duk_small_uint_t elem_size;
60904
60905 h_bufobj = (duk_hbufobj *) curr;
60906 DUK_HBUFOBJ_ASSERT_VALID(h_bufobj);
60907
60908 DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
60909
60910 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
60911 * length downshift won't.
60912 */
60913 if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
60914 duk_uint8_t *data;
60915 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
60916
60917 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
60918 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
60919 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
60920
60921 /* Coerce to number before validating pointers etc so that the
60922 * number coercions in duk_hbufobj_validated_write() are
60923 * guaranteed to be side effect free and not invalidate the
60924 * pointer checks we do here.
60925 */
60926 duk_push_tval(thr, tv_val);
60927 (void) duk_to_number_m1(thr);
60928
60929 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
60930 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
60931 duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
60932 } else {
60933 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
60934 }
60935 duk_pop_unsafe(thr);
60936 goto success_no_arguments_exotic;
60937 }
60938 }
60939#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
60940
60941 DUK_D(DUK_DPRINT("should not happen, key %!O", key));
60942 goto fail_internal; /* should not happen */
60943 }
60944 DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
60945 goto update_old;
60946 }
60947 DUK_UNREACHABLE();
60948
60949 next_in_chain:
60950 /* XXX: option to pretend property doesn't exist if sanity limit is
60951 * hit might be useful.
60952 */
60953 if (DUK_UNLIKELY(sanity-- == 0)) {
60954 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
60955 DUK_WO_NORETURN(return 0;);
60956 }
60957 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
60958 } while (curr != NULL);
60959
60960 /*
60961 * Property not found in prototype chain.
60962 */
60963
60964 DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
60965
60966 if (orig == NULL) {
60967 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
60968 goto fail_base_primitive;
60969 }
60970
60971 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
60972 DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
60973 goto fail_not_extensible;
60974 }
60975
60976 goto create_new;
60977
60978 update_old:
60979
60980 /*
60981 * Update an existing property of the base object.
60982 */
60983
60984 /* [key] */
60985
60986 DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
60987
60988 DUK_ASSERT(orig != NULL);
60989#if defined(DUK_USE_ROM_OBJECTS)
60990 /* This should not happen because DUK_TAG_OBJECT case checks
60991 * for this already, but check just in case.
60992 */
60993 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
60994 goto fail_not_writable;
60995 }
60996#endif
60997
60998 /* Although there are writable virtual properties (e.g. plain buffer
60999 * and buffer object number indices), they are handled before we come
61000 * here.
61001 */
61002 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
61003 DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
61004
61005 /* Array own property .length is handled above. */
61006 DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
61007
61008 if (desc.e_idx >= 0) {
61009 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
61010 DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
61011 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */
61012 /* don't touch property attributes or hash part */
61013 DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
61014 (long) desc.e_idx, (duk_tval *) tv));
61015 } else {
61016 /* Note: array entries are always writable, so the writability check
61017 * above is pointless for them. The check could be avoided with some
61018 * refactoring but is probably not worth it.
61019 */
61020
61021 DUK_ASSERT(desc.a_idx >= 0);
61022 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
61023 DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
61024 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; a_idx may be invalidated */
61025 DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
61026 (long) desc.a_idx, (duk_tval *) tv));
61027 }
61028
61029 /* Regardless of whether property is found in entry or array part,
61030 * it may have arguments exotic behavior (array indices may reside
61031 * in entry part for abandoned / non-existent array parts).
61032 */
61033 goto success_with_arguments_exotic;
61034
61035 create_new:
61036
61037 /*
61038 * Create a new property in the original object.
61039 *
61040 * Exotic properties need to be reconsidered here from a write
61041 * perspective (not just property attributes perspective).
61042 * However, the property does not exist in the object already,
61043 * so this limits the kind of exotic properties that apply.
61044 */
61045
61046 /* [key] */
61047
61048 DUK_DDD(DUK_DDDPRINT("create new property to original object"));
61049
61050 DUK_ASSERT(orig != NULL);
61051
61052 /* Array own property .length is handled above. */
61053 DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
61054
61055#if defined(DUK_USE_ROM_OBJECTS)
61056 /* This should not happen because DUK_TAG_OBJECT case checks
61057 * for this already, but check just in case.
61058 */
61059 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
61060 goto fail_not_writable;
61061 }
61062#endif
61063
61064 /* Not possible because array object 'length' is present
61065 * from its creation and cannot be deleted, and is thus
61066 * caught as an existing property above.
61067 */
61068 DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
61069 key == DUK_HTHREAD_STRING_LENGTH(thr)));
61070
61071 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
61072 arr_idx != DUK__NO_ARRAY_INDEX) {
61073 /* automatic length update */
61074 duk_uint32_t old_len;
61075 duk_harray *a;
61076
61077 a = (duk_harray *) orig;
61078 DUK_HARRAY_ASSERT_VALID(a);
61079
61080 old_len = a->length;
61081
61082 if (arr_idx >= old_len) {
61083 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
61084 "(arr_idx=%ld, old_len=%ld)",
61085 (long) arr_idx, (long) old_len));
61086
61087 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
61088 DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
61089 goto fail_not_writable;
61090 }
61091
61092 /* Note: actual update happens once write has been completed
61093 * without error below. The write should always succeed
61094 * from a specification viewpoint, but we may e.g. run out
61095 * of memory. It's safer in this order.
61096 */
61097
61098 DUK_ASSERT(arr_idx != 0xffffffffUL);
61099 new_array_length = arr_idx + 1; /* flag for later write */
61100 } else {
61101 DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
61102 "(arr_idx=%ld, old_len=%ld)",
61103 (long) arr_idx, (long) old_len));
61104 }
61105 }
61106
61107 /* write_to_array_part: */
61108
61109 /*
61110 * Write to array part?
61111 *
61112 * Note: array abandonding requires a property resize which uses
61113 * 'rechecks' valstack for temporaries and may cause any existing
61114 * valstack pointers to be invalidated. To protect against this,
61115 * tv_obj, tv_key, and tv_val are copies of the original inputs.
61116 */
61117
61118 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
61119 tv = duk__obtain_arridx_slot(thr, arr_idx, orig);
61120 if (tv == NULL) {
61121 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
61122 goto write_to_entry_part;
61123 }
61124
61125 /* prev value must be unused, no decref */
61126 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
61127 DUK_TVAL_SET_TVAL(tv, tv_val);
61128 DUK_TVAL_INCREF(thr, tv);
61129 DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
61130 (long) arr_idx, (duk_tval *) tv));
61131
61132 /* Note: array part values are [[Writable]], [[Enumerable]],
61133 * and [[Configurable]] which matches the required attributes
61134 * here.
61135 */
61136 goto entry_updated;
61137 }
61138
61139 write_to_entry_part:
61140
61141 /*
61142 * Write to entry part
61143 */
61144
61145 /* entry allocation updates hash part and increases the key
61146 * refcount; may need a props allocation resize but doesn't
61147 * 'recheck' the valstack.
61148 */
61149 e_idx = duk__hobject_alloc_entry_checked(thr, orig, key);
61150 DUK_ASSERT(e_idx >= 0);
61151
61152 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
61153 /* prev value can be garbage, no decref */
61154 DUK_TVAL_SET_TVAL(tv, tv_val);
61155 DUK_TVAL_INCREF(thr, tv);
61156 DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
61157 goto entry_updated;
61158
61159 entry_updated:
61160
61161 /*
61162 * Possible pending array length update, which must only be done
61163 * if the actual entry write succeeded.
61164 */
61165
61166 if (new_array_length > 0) {
61167 /* Note: zero works as a "no update" marker because the new length
61168 * can never be zero after a new property is written.
61169 */
61170
61171 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig));
61172
61173 DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
61174 (long) new_array_length));
61175
61176 ((duk_harray *) orig)->length = new_array_length;
61177 }
61178
61179 /*
61180 * Arguments exotic behavior not possible for new properties: all
61181 * magically bound properties are initially present in the arguments
61182 * object, and if they are deleted, the binding is also removed from
61183 * parameter map.
61184 */
61185
61186 goto success_no_arguments_exotic;
61187
61188 success_with_arguments_exotic:
61189
61190 /*
61191 * Arguments objects have exotic [[DefineOwnProperty]] which updates
61192 * the internal 'map' of arguments for writes to currently mapped
61193 * arguments. More conretely, writes to mapped arguments generate
61194 * a write to a bound variable.
61195 *
61196 * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
61197 * data properties and new properties, but not for existing accessors.
61198 * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
61199 * have a Desc with 'Value' (and possibly other properties too), and
61200 * we end up in step 5.b.i.
61201 */
61202
61203 if (arr_idx != DUK__NO_ARRAY_INDEX &&
61204 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
61205 /* Note: only numbered indices are relevant, so arr_idx fast reject
61206 * is good (this is valid unless there are more than 4**32-1 arguments).
61207 */
61208
61209 DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
61210
61211 /* Note: we can reuse 'desc' here */
61212
61213 /* XXX: top of stack must contain value, which helper doesn't touch,
61214 * rework to use tv_val directly?
61215 */
61216
61217 duk_push_tval(thr, tv_val);
61218 (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
61219 duk_pop_unsafe(thr);
61220 }
61221 /* fall thru */
61222
61223 success_no_arguments_exotic:
61224 /* shared exit path now */
61225 DUK_DDD(DUK_DDDPRINT("result: success"));
61226 duk_pop_unsafe(thr); /* remove key */
61227 return 1;
61228
61229#if defined(DUK_USE_ES6_PROXY)
61230 fail_proxy_rejected:
61231 DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
61232 if (throw_flag) {
61233 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
61234 DUK_WO_NORETURN(return 0;);
61235 }
61236 /* Note: no key on stack */
61237 return 0;
61238#endif
61239
61240 fail_base_primitive:
61241 DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
61242 if (throw_flag) {
61243#if defined(DUK_USE_PARANOID_ERRORS)
61244 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
61245#else
61246 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
61247 duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
61248#endif
61249 DUK_WO_NORETURN(return 0;);
61250 }
61251 duk_pop_unsafe(thr); /* remove key */
61252 return 0;
61253
61254 fail_not_extensible:
61255 DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
61256 if (throw_flag) {
61257 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
61258 DUK_WO_NORETURN(return 0;);
61259 }
61260 duk_pop_unsafe(thr); /* remove key */
61261 return 0;
61262
61263 fail_not_writable:
61264 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
61265 if (throw_flag) {
61266 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
61267 DUK_WO_NORETURN(return 0;);
61268 }
61269 duk_pop_unsafe(thr); /* remove key */
61270 return 0;
61271
61272#if defined(DUK_USE_ROM_OBJECTS)
61273 fail_not_writable_no_pop:
61274 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
61275 if (throw_flag) {
61276 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
61277 DUK_WO_NORETURN(return 0;);
61278 }
61279 return 0;
61280#endif
61281
61282 fail_array_length_partial:
61283 DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful"));
61284 if (throw_flag) {
61285 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
61286 DUK_WO_NORETURN(return 0;);
61287 }
61288 duk_pop_unsafe(thr); /* remove key */
61289 return 0;
61290
61291 fail_no_setter:
61292 DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
61293 if (throw_flag) {
61294 DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
61295 DUK_WO_NORETURN(return 0;);
61296 }
61297 duk_pop_unsafe(thr); /* remove key */
61298 return 0;
61299
61300 fail_internal:
61301 DUK_DDD(DUK_DDDPRINT("result: error, internal"));
61302 if (throw_flag) {
61303 DUK_ERROR_INTERNAL(thr);
61304 DUK_WO_NORETURN(return 0;);
61305 }
61306 duk_pop_unsafe(thr); /* remove key */
61307 return 0;
61308}
61309
61310/*
61311 * ECMAScript compliant [[Delete]](P, Throw).
61312 */
61313
61314DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
61315 duk_propdesc desc;
61316 duk_tval *tv;
61317 duk_uint32_t arr_idx;
61318 duk_bool_t throw_flag;
61319 duk_bool_t force_flag;
61320
61321 throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
61322 force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
61323
61324 DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
61325 (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
61326 (duk_heaphdr *) obj, (duk_heaphdr *) key));
61327
61328 DUK_ASSERT(thr != NULL);
61329 DUK_ASSERT(thr->heap != NULL);
61330 DUK_ASSERT(obj != NULL);
61331 DUK_ASSERT(key != NULL);
61332
61333 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
61334
61335 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
61336
61337 /* 0 = don't push current value */
61338 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
61339 DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
61340 goto success;
61341 }
61342
61343#if defined(DUK_USE_ROM_OBJECTS)
61344 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
61345 DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
61346 goto fail_not_configurable;
61347 }
61348#endif
61349
61350 if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
61351 goto fail_not_configurable;
61352 }
61353 if (desc.a_idx < 0 && desc.e_idx < 0) {
61354 /* Currently there are no deletable virtual properties, but
61355 * with force_flag we might attempt to delete one.
61356 */
61357 DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)"));
61358 goto fail_virtual;
61359 }
61360
61361 if (desc.a_idx >= 0) {
61362 DUK_ASSERT(desc.e_idx < 0);
61363
61364 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
61365 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
61366 goto success;
61367 } else {
61368 DUK_ASSERT(desc.a_idx < 0);
61369
61370 /* remove hash entry (no decref) */
61371#if defined(DUK_USE_HOBJECT_HASH_PART)
61372 if (desc.h_idx >= 0) {
61373 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
61374
61375 DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
61376 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
61377 DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
61378 h_base[desc.h_idx] = DUK__HASH_DELETED;
61379 } else {
61380 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
61381 }
61382#else
61383 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
61384#endif
61385
61386 /* Remove value. This requires multiple writes so avoid side
61387 * effects via no-refzero macros so that e_idx is not
61388 * invalidated.
61389 */
61390 DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
61391 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
61392 DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
61393 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
61394 duk_hobject *tmp;
61395
61396 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
61397 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
61398 DUK_UNREF(tmp);
61399 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
61400
61401 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
61402 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
61403 DUK_UNREF(tmp);
61404 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
61405 } else {
61406 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
61407 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
61408 }
61409#if 0
61410 /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
61411 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
61412#endif
61413
61414 /* Remove key. */
61415 DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
61416 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
61417 DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
61418 DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
61419 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
61420 DUK_HSTRING_DECREF_NORZ(thr, key);
61421
61422 /* Trigger refzero side effects only when we're done as a
61423 * finalizer might operate on the object and affect the
61424 * e_idx we're supposed to use.
61425 */
61426 DUK_REFZERO_CHECK_SLOW(thr);
61427 goto success;
61428 }
61429
61430 DUK_UNREACHABLE();
61431
61432 success:
61433 /*
61434 * Argument exotic [[Delete]] behavior (E5 Section 10.6) is
61435 * a post-check, keeping arguments internal 'map' in sync with
61436 * any successful deletes (note that property does not need to
61437 * exist for delete to 'succeed').
61438 *
61439 * Delete key from 'map'. Since 'map' only contains array index
61440 * keys, we can use arr_idx for a fast skip.
61441 */
61442
61443 DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
61444
61445 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
61446 /* Note: only numbered indices are relevant, so arr_idx fast reject
61447 * is good (this is valid unless there are more than 4**32-1 arguments).
61448 */
61449
61450 DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
61451
61452 /* Note: we can reuse 'desc' here */
61453 (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
61454 }
61455
61456 DUK_DDD(DUK_DDDPRINT("delete successful"));
61457 return 1;
61458
61459 fail_virtual: /* just use the same "not configurable" error message */
61460 fail_not_configurable:
61461 DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
61462
61463 if (throw_flag) {
61464 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
61465 DUK_WO_NORETURN(return 0;);
61466 }
61467 return 0;
61468}
61469
61470/*
61471 * DELPROP: ECMAScript property deletion.
61472 */
61473
61474DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
61475 duk_hstring *key = NULL;
61476#if defined(DUK_USE_ES6_PROXY)
61477 duk_propdesc desc;
61478#endif
61479 duk_int_t entry_top;
61480 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
61481 duk_bool_t rc;
61482
61483 DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
61484 (void *) thr, (void *) tv_obj, (void *) tv_key,
61485 (duk_tval *) tv_obj, (duk_tval *) tv_key));
61486
61487 DUK_ASSERT(thr != NULL);
61488 DUK_ASSERT(thr->heap != NULL);
61489 DUK_ASSERT(tv_obj != NULL);
61490 DUK_ASSERT(tv_key != NULL);
61491
61492 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
61493
61494 /* Storing the entry top is cheaper here to ensure stack is correct at exit,
61495 * as there are several paths out.
61496 */
61497 entry_top = duk_get_top(thr);
61498
61499 if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
61500 DUK_TVAL_IS_NULL(tv_obj)) {
61501 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
61502 goto fail_invalid_base_uncond;
61503 }
61504
61505 duk_push_tval(thr, tv_obj);
61506 duk_push_tval(thr, tv_key);
61507
61508 tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2);
61509 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
61510 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
61511 DUK_ASSERT(obj != NULL);
61512
61513#if defined(DUK_USE_ES6_PROXY)
61514 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
61515 duk_hobject *h_target;
61516 duk_bool_t tmp_bool;
61517
61518 /* Note: proxy handling must happen before key is string coerced. */
61519
61520 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
61521 /* -> [ ... obj key trap handler ] */
61522 DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
61523 duk_push_hobject(thr, h_target); /* target */
61524 duk_dup_m4(thr); /* P */
61525 duk_call_method(thr, 2 /*nargs*/);
61526 tmp_bool = duk_to_boolean_top_pop(thr);
61527 if (!tmp_bool) {
61528 goto fail_proxy_rejected; /* retval indicates delete failed */
61529 }
61530
61531 /* Target object must be checked for a conflicting
61532 * non-configurable property.
61533 */
61534 tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
61535 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
61536 DUK_ASSERT(key != NULL);
61537
61538 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
61539 duk_small_int_t desc_reject;
61540
61541 DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
61542 "conflicting property; desc.flags=0x%08lx, "
61543 "desc.get=%p, desc.set=%p",
61544 (duk_heaphdr *) key, (unsigned long) desc.flags,
61545 (void *) desc.get, (void *) desc.set));
61546
61547 desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
61548 if (desc_reject) {
61549 /* unconditional */
61550 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
61551 DUK_WO_NORETURN(return 0;);
61552 }
61553 }
61554 rc = 1; /* success */
61555 goto done_rc;
61556 }
61557
61558 obj = h_target; /* resume delete to target */
61559 }
61560#endif /* DUK_USE_ES6_PROXY */
61561
61562 arr_idx = duk__to_property_key(thr, -1, &key);
61563 DUK_ASSERT(key != NULL);
61564
61565 rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
61566 goto done_rc;
61567 } else if (DUK_TVAL_IS_STRING(tv_obj)) {
61568 /* String has .length and array index virtual properties
61569 * which can't be deleted. No need for a symbol check;
61570 * no offending virtual symbols exist.
61571 */
61572 /* XXX: unnecessary string coercion for array indices,
61573 * intentional to keep small.
61574 */
61575 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
61576 DUK_ASSERT(h != NULL);
61577
61578 arr_idx = duk__to_property_key(thr, -1, &key);
61579 DUK_ASSERT(key != NULL);
61580
61581 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
61582 goto fail_not_configurable;
61583 }
61584
61585 if (arr_idx != DUK__NO_ARRAY_INDEX &&
61586 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
61587 goto fail_not_configurable;
61588 }
61589 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
61590 /* XXX: unnecessary string coercion for array indices,
61591 * intentional to keep small; some overlap with string
61592 * handling.
61593 */
61594 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
61595 DUK_ASSERT(h != NULL);
61596
61597 arr_idx = duk__to_property_key(thr, -1, &key);
61598 DUK_ASSERT(key != NULL);
61599
61600 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
61601 goto fail_not_configurable;
61602 }
61603
61604 if (arr_idx != DUK__NO_ARRAY_INDEX &&
61605 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
61606 goto fail_not_configurable;
61607 }
61608 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
61609 /* Lightfunc has no virtual properties since Duktape 2.2
61610 * so success. Still must coerce key for side effects.
61611 */
61612
61613 arr_idx = duk__to_property_key(thr, -1, &key);
61614 DUK_ASSERT(key != NULL);
61615 DUK_UNREF(key);
61616 }
61617
61618 /* non-object base, no offending virtual property */
61619 rc = 1;
61620 goto done_rc;
61621
61622 done_rc:
61623 duk_set_top_unsafe(thr, entry_top);
61624 return rc;
61625
61626 fail_invalid_base_uncond:
61627 /* Note: unconditional throw */
61628 DUK_ASSERT(duk_get_top(thr) == entry_top);
61629#if defined(DUK_USE_PARANOID_ERRORS)
61630 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
61631#else
61632 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
61633 duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
61634#endif
61635 DUK_WO_NORETURN(return 0;);
61636
61637#if defined(DUK_USE_ES6_PROXY)
61638 fail_proxy_rejected:
61639 if (throw_flag) {
61640 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
61641 DUK_WO_NORETURN(return 0;);
61642 }
61643 duk_set_top_unsafe(thr, entry_top);
61644 return 0;
61645#endif
61646
61647 fail_not_configurable:
61648 if (throw_flag) {
61649 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
61650 DUK_WO_NORETURN(return 0;);
61651 }
61652 duk_set_top_unsafe(thr, entry_top);
61653 return 0;
61654}
61655
61656/*
61657 * Internal helper to define a property with specific flags, ignoring
61658 * normal semantics such as extensibility, write protection etc.
61659 * Overwrites any existing value and attributes unless caller requests
61660 * that value only be updated if it doesn't already exists.
61661 *
61662 * Does not support:
61663 * - virtual properties (error if write attempted)
61664 * - getter/setter properties (error if write attempted)
61665 * - non-default (!= WEC) attributes for array entries (error if attempted)
61666 * - array abandoning: if array part exists, it is always extended
61667 * - array 'length' updating
61668 *
61669 * Stack: [... in_val] -> []
61670 *
61671 * Used for e.g. built-in initialization and environment record
61672 * operations.
61673 */
61674
61675DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
61676 duk_propdesc desc;
61677 duk_uint32_t arr_idx;
61678 duk_int_t e_idx;
61679 duk_tval *tv1 = NULL;
61680 duk_tval *tv2 = NULL;
61681 duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */
61682
61683 DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
61684 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
61685 (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1)));
61686
61687 DUK_ASSERT(thr != NULL);
61688 DUK_ASSERT(thr->heap != NULL);
61689 DUK_ASSERT(obj != NULL);
61690 DUK_ASSERT(key != NULL);
61691 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
61692 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
61693 DUK_ASSERT(duk_is_valid_index(thr, -1)); /* contains value */
61694
61695 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
61696
61697 if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
61698 if (desc.e_idx >= 0) {
61699 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
61700 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
61701 goto pop_exit;
61702 }
61703 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
61704 if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
61705 DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
61706 goto error_internal;
61707 }
61708
61709 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
61710 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
61711 } else if (desc.a_idx >= 0) {
61712 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
61713 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
61714 goto pop_exit;
61715 }
61716 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
61717 if (propflags != DUK_PROPDESC_FLAGS_WEC) {
61718 DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
61719 (unsigned long) propflags));
61720 goto error_internal;
61721 }
61722
61723 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
61724 } else {
61725 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
61726 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
61727 goto pop_exit;
61728 }
61729 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
61730 duk_uint32_t new_len;
61731#if defined(DUK_USE_DEBUG)
61732 duk_uint32_t prev_len;
61733 prev_len = ((duk_harray *) obj)->length;
61734#endif
61735 new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
61736 ((duk_harray *) obj)->length = new_len;
61737 DUK_DD(DUK_DDPRINT("internal define property for array .length: %ld -> %ld",
61738 (long) prev_len, (long) ((duk_harray *) obj)->length));
61739 goto pop_exit;
61740 }
61741 DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure"));
61742 goto error_virtual;
61743 }
61744
61745 goto write_value;
61746 }
61747
61748 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
61749 if (arr_idx != DUK__NO_ARRAY_INDEX) {
61750 DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
61751 DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
61752
61753 tv1 = duk__obtain_arridx_slot(thr, arr_idx, obj);
61754 if (tv1 == NULL) {
61755 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj));
61756 goto write_to_entry_part;
61757 }
61758
61759 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
61760 goto write_value;
61761 }
61762 }
61763
61764 write_to_entry_part:
61765 DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
61766 e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); /* increases key refcount */
61767 DUK_ASSERT(e_idx >= 0);
61768 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
61769 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
61770 /* new entry: previous value is garbage; set to undefined to share write_value */
61771 DUK_TVAL_SET_UNDEFINED(tv1);
61772 goto write_value;
61773
61774 write_value:
61775 /* tv1 points to value storage */
61776
61777 tv2 = duk_require_tval(thr, -1); /* late lookup, avoid side effects */
61778 DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
61779 (duk_tval *) tv1, (duk_tval *) tv2));
61780
61781 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
61782 goto pop_exit;
61783
61784 pop_exit:
61785 duk_pop_unsafe(thr); /* remove in_val */
61786 return;
61787
61788 error_virtual: /* share error message */
61789 error_internal:
61790 DUK_ERROR_INTERNAL(thr);
61791 DUK_WO_NORETURN(return;);
61792}
61793
61794/*
61795 * Fast path for defining array indexed values without interning the key.
61796 * This is used by e.g. code for Array prototype and traceback creation so
61797 * must avoid interning.
61798 */
61799
61800DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
61801 duk_hstring *key;
61802 duk_tval *tv1, *tv2;
61803
61804 DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
61805 "arr_idx=%ld, flags=0x%02lx, val=%!T",
61806 (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
61807 (duk_tval *) duk_get_tval(thr, -1)));
61808
61809 DUK_ASSERT(thr != NULL);
61810 DUK_ASSERT(thr->heap != NULL);
61811 DUK_ASSERT(obj != NULL);
61812 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
61813
61814 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
61815 arr_idx != DUK__NO_ARRAY_INDEX &&
61816 flags == DUK_PROPDESC_FLAGS_WEC) {
61817 DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */
61818
61819 DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
61820
61821 tv1 = duk__obtain_arridx_slot(thr, arr_idx, obj);
61822 if (tv1 == NULL) {
61823 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj));
61824 goto write_slow;
61825 }
61826 tv2 = duk_require_tval(thr, -1);
61827
61828 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
61829
61830 duk_pop_unsafe(thr); /* [ ...val ] -> [ ... ] */
61831 return;
61832 }
61833
61834 write_slow:
61835 DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
61836
61837 key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx);
61838 DUK_ASSERT(key != NULL);
61839 duk_insert(thr, -2); /* [ ... val key ] -> [ ... key val ] */
61840
61841 duk_hobject_define_property_internal(thr, obj, key, flags);
61842
61843 duk_pop_unsafe(thr); /* [ ... key ] -> [ ... ] */
61844}
61845
61846/*
61847 * Internal helpers for managing object 'length'
61848 */
61849
61850DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
61851 duk_double_t val;
61852
61853 DUK_CTX_ASSERT_VALID(thr);
61854 DUK_ASSERT(obj != NULL);
61855
61856 /* Fast path for Arrays. */
61857 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
61858 return ((duk_harray *) obj)->length;
61859 }
61860
61861 /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */
61862 duk_push_hobject(thr, obj);
61863 duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH);
61864 (void) duk_hobject_getprop(thr,
61865 DUK_GET_TVAL_NEGIDX(thr, -2),
61866 DUK_GET_TVAL_NEGIDX(thr, -1));
61867 val = duk_to_number_m1(thr);
61868 duk_pop_3_unsafe(thr);
61869
61870 /* This isn't part of ECMAScript semantics; return a value within
61871 * duk_size_t range, or 0 otherwise.
61872 */
61873 if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
61874 return (duk_size_t) val;
61875 }
61876 return 0;
61877}
61878
61879/*
61880 * Fast finalizer check for an object. Walks the prototype chain, checking
61881 * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept
61882 * in sync with the actual property when setting/removing the finalizer.
61883 */
61884
61885#if defined(DUK_USE_HEAPPTR16)
61886DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) {
61887#else
61888DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) {
61889#endif
61890 duk_uint_t sanity;
61891
61892 DUK_ASSERT(obj != NULL);
61893
61894 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
61895 do {
61896 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) {
61897 return 1;
61898 }
61899 if (DUK_UNLIKELY(sanity-- == 0)) {
61900 DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false"));
61901 return 0;
61902 }
61903#if defined(DUK_USE_HEAPPTR16)
61904 DUK_ASSERT(heap != NULL);
61905 obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj);
61906#else
61907 obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */
61908#endif
61909 } while (obj != NULL);
61910
61911 return 0;
61912}
61913
61914/*
61915 * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
61916 *
61917 * [ ... key ] -> [ ... desc/undefined ]
61918 */
61919
61920DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) {
61921 duk_hobject *obj;
61922 duk_hstring *key;
61923 duk_propdesc pd;
61924
61925 DUK_ASSERT(thr != NULL);
61926 DUK_ASSERT(thr->heap != NULL);
61927
61928 obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
61929 key = duk_to_property_key_hstring(thr, -1);
61930 DUK_ASSERT(key != NULL);
61931
61932 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
61933
61934 if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) {
61935 duk_push_undefined(thr);
61936 duk_remove_m2(thr);
61937 return;
61938 }
61939
61940 duk_push_object(thr);
61941
61942 /* [ ... key value desc ] */
61943
61944 if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
61945 /* If a setter/getter is missing (undefined), the descriptor must
61946 * still have the property present with the value 'undefined'.
61947 */
61948 if (pd.get) {
61949 duk_push_hobject(thr, pd.get);
61950 } else {
61951 duk_push_undefined(thr);
61952 }
61953 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET);
61954 if (pd.set) {
61955 duk_push_hobject(thr, pd.set);
61956 } else {
61957 duk_push_undefined(thr);
61958 }
61959 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET);
61960 } else {
61961 duk_dup_m2(thr);
61962 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE);
61963 duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd));
61964 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE);
61965 }
61966 duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd));
61967 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE);
61968 duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
61969 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE);
61970
61971 /* [ ... key value desc ] */
61972
61973 duk_replace(thr, -3);
61974 duk_pop_unsafe(thr); /* -> [ ... desc ] */
61975}
61976
61977/*
61978 * NormalizePropertyDescriptor() related helper.
61979 *
61980 * Internal helper which validates and normalizes a property descriptor
61981 * represented as an ECMAScript object (e.g. argument to defineProperty()).
61982 * The output of this conversion is a set of defprop_flags and possibly
61983 * some values pushed on the value stack to (1) ensure borrowed pointers
61984 * remain valid, and (2) avoid unnecessary pops for footprint reasons.
61985 * Caller must manage stack top carefully because the number of values
61986 * pushed depends on the input property descriptor.
61987 *
61988 * The original descriptor object must not be altered in the process.
61989 */
61990
61991/* XXX: very basic optimization -> duk_get_prop_stridx_top */
61992
61993DUK_INTERNAL
61994void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
61995 duk_idx_t idx_in,
61996 duk_uint_t *out_defprop_flags,
61997 duk_idx_t *out_idx_value,
61998 duk_hobject **out_getter,
61999 duk_hobject **out_setter) {
62000 duk_idx_t idx_value = -1;
62001 duk_hobject *getter = NULL;
62002 duk_hobject *setter = NULL;
62003 duk_bool_t is_data_desc = 0;
62004 duk_bool_t is_acc_desc = 0;
62005 duk_uint_t defprop_flags = 0;
62006
62007 DUK_ASSERT(out_defprop_flags != NULL);
62008 DUK_ASSERT(out_idx_value != NULL);
62009 DUK_ASSERT(out_getter != NULL);
62010 DUK_ASSERT(out_setter != NULL);
62011 DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */
62012
62013 /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
62014 idx_in = duk_require_normalize_index(thr, idx_in);
62015 (void) duk_require_hobject(thr, idx_in);
62016
62017 /* The coercion order must match the ToPropertyDescriptor() algorithm
62018 * so that side effects in coercion happen in the correct order.
62019 * (This order also happens to be compatible with duk_def_prop(),
62020 * although it doesn't matter in practice.)
62021 */
62022
62023 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) {
62024 is_data_desc = 1;
62025 defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
62026 idx_value = duk_get_top_index(thr);
62027 }
62028
62029 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
62030 is_data_desc = 1;
62031 if (duk_to_boolean_top_pop(thr)) {
62032 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
62033 } else {
62034 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
62035 }
62036 }
62037
62038 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) {
62039 duk_tval *tv = duk_require_tval(thr, -1);
62040 duk_hobject *h_get;
62041
62042 if (DUK_TVAL_IS_UNDEFINED(tv)) {
62043 /* undefined is accepted */
62044 DUK_ASSERT(getter == NULL);
62045 } else {
62046 /* NOTE: lightfuncs are coerced to full functions because
62047 * lightfuncs don't fit into a property value slot. This
62048 * has some side effects, see test-dev-lightfunc-accessor.js.
62049 */
62050 h_get = duk_get_hobject_promote_lfunc(thr, -1);
62051 if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
62052 goto type_error;
62053 }
62054 getter = h_get;
62055 }
62056 is_acc_desc = 1;
62057 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
62058 }
62059
62060 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) {
62061 duk_tval *tv = duk_require_tval(thr, -1);
62062 duk_hobject *h_set;
62063
62064 if (DUK_TVAL_IS_UNDEFINED(tv)) {
62065 /* undefined is accepted */
62066 DUK_ASSERT(setter == NULL);
62067 } else {
62068 /* NOTE: lightfuncs are coerced to full functions because
62069 * lightfuncs don't fit into a property value slot. This
62070 * has some side effects, see test-dev-lightfunc-accessor.js.
62071 */
62072 h_set = duk_get_hobject_promote_lfunc(thr, -1);
62073 if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
62074 goto type_error;
62075 }
62076 setter = h_set;
62077 }
62078 is_acc_desc = 1;
62079 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
62080 }
62081
62082 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) {
62083 if (duk_to_boolean_top_pop(thr)) {
62084 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
62085 } else {
62086 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
62087 }
62088 }
62089
62090 if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) {
62091 if (duk_to_boolean_top_pop(thr)) {
62092 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
62093 } else {
62094 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
62095 }
62096 }
62097
62098 if (is_data_desc && is_acc_desc) {
62099 goto type_error;
62100 }
62101
62102 *out_defprop_flags = defprop_flags;
62103 *out_idx_value = idx_value;
62104 *out_getter = getter;
62105 *out_setter = setter;
62106
62107 /* [ ... [multiple values] ] */
62108 return;
62109
62110 type_error:
62111 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
62112 DUK_WO_NORETURN(return;);
62113}
62114
62115/*
62116 * Object.defineProperty() related helper (E5 Section 15.2.3.6).
62117 * Also handles ES2015 Reflect.defineProperty().
62118 *
62119 * Inlines all [[DefineOwnProperty]] exotic behaviors.
62120 *
62121 * Note: ECMAScript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
62122 * implemented directly, but Object.defineProperty() serves its purpose.
62123 * We don't need the [[DefineOwnProperty]] internally and we don't have a
62124 * property descriptor with 'missing values' so it's easier to avoid it
62125 * entirely.
62126 *
62127 * Note: this is only called for actual objects, not primitive values.
62128 * This must support virtual properties for full objects (e.g. Strings)
62129 * but not for plain values (e.g. strings). Lightfuncs, even though
62130 * primitive in a sense, are treated like objects and accepted as target
62131 * values.
62132 */
62133
62134/* XXX: this is a major target for size optimization */
62135DUK_INTERNAL
62136duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
62137 duk_uint_t defprop_flags,
62138 duk_hobject *obj,
62139 duk_hstring *key,
62140 duk_idx_t idx_value,
62141 duk_hobject *get,
62142 duk_hobject *set,
62143 duk_bool_t throw_flag) {
62144 duk_uint32_t arr_idx;
62145 duk_tval tv;
62146 duk_bool_t has_enumerable;
62147 duk_bool_t has_configurable;
62148 duk_bool_t has_writable;
62149 duk_bool_t has_value;
62150 duk_bool_t has_get;
62151 duk_bool_t has_set;
62152 duk_bool_t is_enumerable;
62153 duk_bool_t is_configurable;
62154 duk_bool_t is_writable;
62155 duk_bool_t force_flag;
62156 duk_small_uint_t new_flags;
62157 duk_propdesc curr;
62158 duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */
62159 duk_uint32_t arrlen_old_len;
62160 duk_uint32_t arrlen_new_len;
62161 duk_bool_t pending_write_protect;
62162
62163 DUK_ASSERT(thr != NULL);
62164 DUK_ASSERT(thr->heap != NULL);
62165 DUK_ASSERT(obj != NULL);
62166 DUK_ASSERT(key != NULL);
62167 /* idx_value may be < 0 (no value), set and get may be NULL */
62168
62169 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
62170
62171 /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
62172
62173 has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
62174 has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
62175 has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
62176 has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
62177 has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
62178 has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
62179 is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
62180 is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
62181 is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
62182 force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
62183
62184 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
62185
62186 arridx_new_array_length = 0;
62187 pending_write_protect = 0;
62188 arrlen_old_len = 0;
62189 arrlen_new_len = 0;
62190
62191 DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
62192 "has_configurable=%ld is_configurable=%ld "
62193 "has_writable=%ld is_writable=%ld "
62194 "has_value=%ld value=%!T "
62195 "has_get=%ld get=%p=%!O "
62196 "has_set=%ld set=%p=%!O "
62197 "arr_idx=%ld throw_flag=!%ld",
62198 (long) has_enumerable, (long) is_enumerable,
62199 (long) has_configurable, (long) is_configurable,
62200 (long) has_writable, (long) is_writable,
62201 (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL),
62202 (long) has_get, (void *) get, (duk_heaphdr *) get,
62203 (long) has_set, (void *) set, (duk_heaphdr *) set,
62204 (long) arr_idx, (long) throw_flag));
62205
62206 /*
62207 * Array exotic behaviors can be implemented at this point. The local variables
62208 * are essentially a 'value copy' of the input descriptor (Desc), which is modified
62209 * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
62210 */
62211
62212 if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
62213 goto skip_array_exotic;
62214 }
62215
62216 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
62217 duk_harray *a;
62218
62219 /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
62220 if (!has_value) {
62221 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
62222 goto skip_array_exotic;
62223 }
62224
62225 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
62226
62227 /*
62228 * Get old and new length
62229 */
62230
62231 a = (duk_harray *) obj;
62232 DUK_HARRAY_ASSERT_VALID(a);
62233 arrlen_old_len = a->length;
62234
62235 DUK_ASSERT(idx_value >= 0);
62236 arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value));
62237 duk_push_u32(thr, arrlen_new_len);
62238 duk_replace(thr, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
62239
62240 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
62241
62242 if (arrlen_new_len >= arrlen_old_len) {
62243 /* standard behavior, step 3.f.i */
62244 DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
62245 goto skip_array_exotic;
62246 }
62247 DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
62248
62249 /* XXX: consolidated algorithm step 15.f -> redundant? */
62250 if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
62251 /* Array .length is always non-configurable; if it's also
62252 * non-writable, don't allow it to be written.
62253 */
62254 goto fail_not_configurable;
62255 }
62256
62257 /* steps 3.h and 3.i */
62258 if (has_writable && !is_writable) {
62259 DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
62260 is_writable = 1;
62261 pending_write_protect = 1;
62262 }
62263
62264 /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
62265 } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
62266 /* XXX: any chance of unifying this with the 'length' key handling? */
62267
62268 /* E5 Section 15.4.5.1, step 4 */
62269 duk_uint32_t old_len;
62270 duk_harray *a;
62271
62272 a = (duk_harray *) obj;
62273 DUK_HARRAY_ASSERT_VALID(a);
62274
62275 old_len = a->length;
62276
62277 if (arr_idx >= old_len) {
62278 DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
62279 "(arr_idx=%ld, old_len=%ld)",
62280 (long) arr_idx, (long) old_len));
62281
62282 if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
62283 /* Array .length is always non-configurable, so
62284 * if it's also non-writable, don't allow a value
62285 * write. With force flag allow writing.
62286 */
62287 goto fail_not_configurable;
62288 }
62289
62290 /* actual update happens once write has been completed without
62291 * error below.
62292 */
62293 DUK_ASSERT(arr_idx != 0xffffffffUL);
62294 arridx_new_array_length = arr_idx + 1;
62295 } else {
62296 DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
62297 "(arr_idx=%ld, old_len=%ld) -> standard behavior",
62298 (long) arr_idx, (long) old_len));
62299 }
62300 }
62301 skip_array_exotic:
62302
62303 /* XXX: There is currently no support for writing buffer object
62304 * indexed elements here. Attempt to do so will succeed and
62305 * write a concrete property into the buffer object. This should
62306 * be fixed at some point but because buffers are a custom feature
62307 * anyway, this is relatively unimportant.
62308 */
62309
62310 /*
62311 * Actual Object.defineProperty() default algorithm.
62312 */
62313
62314 /*
62315 * First check whether property exists; if not, simple case. This covers
62316 * steps 1-4.
62317 */
62318
62319 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
62320 DUK_DDD(DUK_DDDPRINT("property does not exist"));
62321
62322 if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
62323 goto fail_not_extensible;
62324 }
62325
62326#if defined(DUK_USE_ROM_OBJECTS)
62327 /* ROM objects are never extensible but force flag may
62328 * allow us to come here anyway.
62329 */
62330 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj));
62331 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
62332 DUK_D(DUK_DPRINT("attempt to define property on a read-only target object"));
62333 goto fail_not_configurable;
62334 }
62335#endif
62336
62337 /* XXX: share final setting code for value and flags? difficult because
62338 * refcount code is different. Share entry allocation? But can't allocate
62339 * until array index checked.
62340 */
62341
62342 /* steps 4.a and 4.b are tricky */
62343 if (has_set || has_get) {
62344 duk_int_t e_idx;
62345
62346 DUK_DDD(DUK_DDDPRINT("create new accessor property"));
62347
62348 DUK_ASSERT(has_set || set == NULL);
62349 DUK_ASSERT(has_get || get == NULL);
62350 DUK_ASSERT(!has_value);
62351 DUK_ASSERT(!has_writable);
62352
62353 new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */
62354 if (has_enumerable && is_enumerable) {
62355 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
62356 }
62357 if (has_configurable && is_configurable) {
62358 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
62359 }
62360
62361 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
62362 DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
62363 duk__abandon_array_part(thr, obj);
62364 }
62365
62366 /* write to entry part */
62367 e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
62368 DUK_ASSERT(e_idx >= 0);
62369
62370 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
62371 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
62372 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
62373 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
62374
62375 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
62376 goto success_exotics;
62377 } else {
62378 duk_int_t e_idx;
62379 duk_tval *tv2;
62380
62381 DUK_DDD(DUK_DDDPRINT("create new data property"));
62382
62383 DUK_ASSERT(!has_set);
62384 DUK_ASSERT(!has_get);
62385
62386 new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */
62387 if (has_writable && is_writable) {
62388 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
62389 }
62390 if (has_enumerable && is_enumerable) {
62391 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
62392 }
62393 if (has_configurable && is_configurable) {
62394 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
62395 }
62396 if (has_value) {
62397 duk_tval *tv_tmp = duk_require_tval(thr, idx_value);
62398 DUK_TVAL_SET_TVAL(&tv, tv_tmp);
62399 } else {
62400 DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
62401 }
62402
62403 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
62404 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
62405 DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
62406 tv2 = duk__obtain_arridx_slot(thr, arr_idx, obj);
62407 if (tv2 == NULL) {
62408 DUK_DDD(DUK_DDDPRINT("failed writing to array part, abandoned array"));
62409 } else {
62410 DUK_DDD(DUK_DDDPRINT("success in writing to array part"));
62411 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(obj));
62412 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv2));
62413 DUK_TVAL_SET_TVAL(tv2, &tv);
62414 DUK_TVAL_INCREF(thr, tv2);
62415 goto success_exotics;
62416 }
62417 } else {
62418 DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
62419 duk__abandon_array_part(thr, obj);
62420 }
62421 /* fall through */
62422 }
62423
62424 /* write to entry part */
62425 e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
62426 DUK_ASSERT(e_idx >= 0);
62427 tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
62428 DUK_TVAL_SET_TVAL(tv2, &tv);
62429 DUK_TVAL_INCREF(thr, tv2);
62430
62431 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
62432 goto success_exotics;
62433 }
62434 DUK_UNREACHABLE();
62435 }
62436
62437 /* we currently assume virtual properties are not configurable (as none of them are) */
62438 DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
62439
62440 /* [obj key desc value get set curr_value] */
62441
62442 /*
62443 * Property already exists. Steps 5-6 detect whether any changes need
62444 * to be made.
62445 */
62446
62447 if (has_enumerable) {
62448 if (is_enumerable) {
62449 if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
62450 goto need_check;
62451 }
62452 } else {
62453 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
62454 goto need_check;
62455 }
62456 }
62457 }
62458 if (has_configurable) {
62459 if (is_configurable) {
62460 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
62461 goto need_check;
62462 }
62463 } else {
62464 if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
62465 goto need_check;
62466 }
62467 }
62468 }
62469 if (has_value) {
62470 duk_tval *tmp1;
62471 duk_tval *tmp2;
62472
62473 /* attempt to change from accessor to data property */
62474 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62475 goto need_check;
62476 }
62477
62478 tmp1 = duk_require_tval(thr, -1); /* curr value */
62479 tmp2 = duk_require_tval(thr, idx_value); /* new value */
62480 if (!duk_js_samevalue(tmp1, tmp2)) {
62481 goto need_check;
62482 }
62483 }
62484 if (has_writable) {
62485 /* attempt to change from accessor to data property */
62486 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62487 goto need_check;
62488 }
62489
62490 if (is_writable) {
62491 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
62492 goto need_check;
62493 }
62494 } else {
62495 if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
62496 goto need_check;
62497 }
62498 }
62499 }
62500 if (has_set) {
62501 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62502 if (set != curr.set) {
62503 goto need_check;
62504 }
62505 } else {
62506 goto need_check;
62507 }
62508 }
62509 if (has_get) {
62510 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62511 if (get != curr.get) {
62512 goto need_check;
62513 }
62514 } else {
62515 goto need_check;
62516 }
62517 }
62518
62519 /* property exists, either 'desc' is empty, or all values
62520 * match (SameValue)
62521 */
62522 goto success_no_exotics;
62523
62524 need_check:
62525
62526 /*
62527 * Some change(s) need to be made. Steps 7-11.
62528 */
62529
62530 /* shared checks for all descriptor types */
62531 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
62532 if (has_configurable && is_configurable) {
62533 goto fail_not_configurable;
62534 }
62535 if (has_enumerable) {
62536 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
62537 if (!is_enumerable) {
62538 goto fail_not_configurable;
62539 }
62540 } else {
62541 if (is_enumerable) {
62542 goto fail_not_configurable;
62543 }
62544 }
62545 }
62546 }
62547
62548 /* Virtual properties don't have backing so they can't mostly be
62549 * edited. Some virtual properties are, however, writable: for
62550 * example, virtual index properties of buffer objects and Array
62551 * instance .length. These are not configurable so the checks
62552 * above mostly cover attempts to change them, except when the
62553 * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in
62554 * that case we can't forcibly change the property attributes
62555 * because they don't have concrete backing.
62556 */
62557
62558 /* XXX: for ROM objects too it'd be best if value modify was
62559 * allowed if the value matches SameValue.
62560 */
62561 /* Reject attempt to change a read-only object. */
62562#if defined(DUK_USE_ROM_OBJECTS)
62563 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
62564 DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
62565 goto fail_not_configurable;
62566 }
62567#endif
62568
62569 /* descriptor type specific checks */
62570 if (has_set || has_get) {
62571 /* IsAccessorDescriptor(desc) == true */
62572 DUK_ASSERT(!has_writable);
62573 DUK_ASSERT(!has_value);
62574
62575 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62576 /* curr and desc are accessors */
62577 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
62578 if (has_set && set != curr.set) {
62579 goto fail_not_configurable;
62580 }
62581 if (has_get && get != curr.get) {
62582 goto fail_not_configurable;
62583 }
62584 }
62585 } else {
62586 duk_bool_t rc;
62587 duk_tval *tv1;
62588
62589 /* curr is data, desc is accessor */
62590 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
62591 goto fail_not_configurable;
62592 }
62593
62594 DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
62595 if (curr.a_idx >= 0) {
62596 DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
62597 duk__abandon_array_part(thr, obj);
62598 duk_pop_unsafe(thr); /* remove old value */
62599 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
62600 DUK_UNREF(rc);
62601 DUK_ASSERT(rc != 0);
62602 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
62603 }
62604 if (curr.e_idx < 0) {
62605 DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0);
62606 goto fail_virtual; /* safeguard for virtual property */
62607 }
62608
62609 DUK_ASSERT(curr.e_idx >= 0);
62610 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
62611
62612 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
62613 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1); /* XXX: just decref */
62614
62615 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
62616 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
62617 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
62618 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
62619
62620 DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
62621 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
62622 /* Update curr.flags; faster than a re-lookup. */
62623 curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
62624 curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR;
62625 }
62626 } else if (has_value || has_writable) {
62627 /* IsDataDescriptor(desc) == true */
62628 DUK_ASSERT(!has_set);
62629 DUK_ASSERT(!has_get);
62630
62631 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
62632 duk_hobject *tmp;
62633
62634 /* curr is accessor, desc is data */
62635 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
62636 goto fail_not_configurable;
62637 }
62638
62639 /* curr is accessor -> cannot be in array part. */
62640 DUK_ASSERT(curr.a_idx < 0);
62641 if (curr.e_idx < 0) {
62642 goto fail_virtual; /* safeguard; no virtual accessors now */
62643 }
62644
62645 DUK_DDD(DUK_DDDPRINT("convert property to data property"));
62646
62647 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
62648 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
62649 DUK_UNREF(tmp);
62650 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
62651 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
62652 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
62653 DUK_UNREF(tmp);
62654 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
62655 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
62656
62657 DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
62658 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
62659 DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
62660
62661 DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
62662 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
62663
62664 /* Update curr.flags; faster than a re-lookup. */
62665 curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR);
62666 } else {
62667 /* curr and desc are data */
62668 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
62669 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
62670 goto fail_not_configurable;
62671 }
62672 /* Note: changing from writable to non-writable is OK */
62673 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
62674 duk_tval *tmp1 = duk_require_tval(thr, -1); /* curr value */
62675 duk_tval *tmp2 = duk_require_tval(thr, idx_value); /* new value */
62676 if (!duk_js_samevalue(tmp1, tmp2)) {
62677 goto fail_not_configurable;
62678 }
62679 }
62680 }
62681 }
62682 } else {
62683 /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
62684 * only has [[Enumerable]] or [[Configurable]] flag updates, which are
62685 * allowed at this point.
62686 */
62687
62688 DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
62689 }
62690
62691 /*
62692 * Start doing property attributes updates. Steps 12-13.
62693 *
62694 * Start by computing new attribute flags without writing yet.
62695 * Property type conversion is done above if necessary.
62696 */
62697
62698 new_flags = curr.flags;
62699
62700 if (has_enumerable) {
62701 if (is_enumerable) {
62702 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
62703 } else {
62704 new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
62705 }
62706 }
62707 if (has_configurable) {
62708 if (is_configurable) {
62709 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
62710 } else {
62711 new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
62712 }
62713 }
62714 if (has_writable) {
62715 if (is_writable) {
62716 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
62717 } else {
62718 new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
62719 }
62720 }
62721
62722 /* XXX: write protect after flag? -> any chance of handling it here? */
62723
62724 DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
62725 (unsigned long) new_flags));
62726
62727 /*
62728 * Check whether we need to abandon an array part (if it exists)
62729 */
62730
62731 if (curr.a_idx >= 0) {
62732 duk_bool_t rc;
62733
62734 DUK_ASSERT(curr.e_idx < 0);
62735
62736 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
62737 duk_tval *tv1, *tv2;
62738
62739 DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
62740
62741 DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
62742 DUK_ASSERT(!has_set);
62743 DUK_ASSERT(!has_get);
62744 DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */
62745
62746 tv2 = duk_require_tval(thr, idx_value);
62747 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
62748 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */
62749 goto success_exotics;
62750 }
62751
62752 DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
62753 duk__abandon_array_part(thr, obj);
62754 duk_pop_unsafe(thr); /* remove old value */
62755 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
62756 DUK_UNREF(rc);
62757 DUK_ASSERT(rc != 0);
62758 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
62759 }
62760
62761 DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
62762
62763 /* Array case is handled comprehensively above: either in entry
62764 * part or a virtual property.
62765 */
62766 DUK_ASSERT(curr.a_idx < 0);
62767
62768 DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
62769 if (curr.e_idx >= 0) {
62770 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
62771 } else {
62772 /* For Array .length the only allowed transition is for .length
62773 * to become non-writable.
62774 */
62775 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
62776 duk_harray *a;
62777 a = (duk_harray *) obj;
62778 DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx", (unsigned long) new_flags));
62779 DUK_HARRAY_ASSERT_VALID(a);
62780 if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) {
62781 DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail"));
62782 goto fail_virtual;
62783 }
62784 if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) {
62785 DUK_HARRAY_SET_LENGTH_WRITABLE(a);
62786 } else {
62787 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
62788 }
62789 }
62790 }
62791
62792 if (has_set) {
62793 duk_hobject *tmp;
62794
62795 /* Virtual properties are non-configurable but with a 'force'
62796 * flag we might come here so check explicitly for virtual.
62797 */
62798 if (curr.e_idx < 0) {
62799 goto fail_virtual;
62800 }
62801
62802 DUK_DDD(DUK_DDDPRINT("update existing property setter"));
62803 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
62804
62805 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
62806 DUK_UNREF(tmp);
62807 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
62808 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
62809 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
62810 }
62811 if (has_get) {
62812 duk_hobject *tmp;
62813
62814 if (curr.e_idx < 0) {
62815 goto fail_virtual;
62816 }
62817
62818 DUK_DDD(DUK_DDDPRINT("update existing property getter"));
62819 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
62820
62821 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
62822 DUK_UNREF(tmp);
62823 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
62824 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
62825 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
62826 }
62827 if (has_value) {
62828 duk_tval *tv1, *tv2;
62829
62830 DUK_DDD(DUK_DDDPRINT("update existing property value"));
62831
62832 if (curr.e_idx >= 0) {
62833 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
62834 tv2 = duk_require_tval(thr, idx_value);
62835 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
62836 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */
62837 } else {
62838 DUK_ASSERT(curr.a_idx < 0); /* array part case handled comprehensively previously */
62839
62840 DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property"));
62841 /* XXX: Uint8Array and other typed array virtual writes not currently
62842 * handled.
62843 */
62844 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
62845 duk_harray *a;
62846 a = (duk_harray *) obj;
62847 DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld", (long) arrlen_new_len));
62848 DUK_HARRAY_ASSERT_VALID(a);
62849 a->length = arrlen_new_len;
62850 } else {
62851 goto fail_virtual; /* should not happen */
62852 }
62853 }
62854 }
62855
62856 /*
62857 * Standard algorithm succeeded without errors, check for exotic post-behaviors.
62858 *
62859 * Arguments exotic behavior in E5 Section 10.6 occurs after the standard
62860 * [[DefineOwnProperty]] has completed successfully.
62861 *
62862 * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
62863 * prior to the default [[DefineOwnProperty]], but:
62864 * - for an array index key (e.g. "10") the final 'length' update occurs here
62865 * - for 'length' key the element deletion and 'length' update occurs here
62866 */
62867
62868 success_exotics:
62869
62870 /* curr.a_idx or curr.e_idx may have been invalidated by side effects
62871 * above.
62872 */
62873
62874 /* [obj key desc value get set curr_value] */
62875
62876 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
62877 duk_harray *a;
62878
62879 a = (duk_harray *) obj;
62880 DUK_HARRAY_ASSERT_VALID(a);
62881
62882 if (arridx_new_array_length > 0) {
62883 /*
62884 * Note: zero works as a "no update" marker because the new length
62885 * can never be zero after a new property is written.
62886 */
62887
62888 /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
62889
62890 DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
62891 (long) arridx_new_array_length));
62892
62893 a->length = arridx_new_array_length;
62894 }
62895
62896 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
62897 /*
62898 * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
62899 * the error case 3.l.iii and the success case 3.m-3.n.
62900 */
62901
62902 /* XXX: investigate whether write protect can be handled above, if we
62903 * just update length here while ignoring its protected status
62904 */
62905
62906 duk_uint32_t result_len;
62907 duk_bool_t rc;
62908
62909 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
62910 "doing array element deletion and length update"));
62911
62912 rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
62913
62914 /* update length (curr points to length, and we assume it's still valid) */
62915 DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
62916
62917 a->length = result_len;
62918
62919 if (pending_write_protect) {
62920 DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
62921 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
62922 }
62923
62924 /* XXX: shrink array allocation or entries compaction here? */
62925 if (!rc) {
62926 DUK_DD(DUK_DDPRINT("array length write only partially successful"));
62927 goto fail_not_configurable;
62928 }
62929 }
62930 } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
62931 duk_hobject *map;
62932 duk_hobject *varenv;
62933
62934 DUK_ASSERT(arridx_new_array_length == 0);
62935 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */
62936
62937 map = NULL;
62938 varenv = NULL;
62939 if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
62940 goto success_no_exotics;
62941 }
62942 DUK_ASSERT(map != NULL);
62943 DUK_ASSERT(varenv != NULL);
62944
62945 /* [obj key desc value get set curr_value varname] */
62946
62947 if (has_set || has_get) {
62948 /* = IsAccessorDescriptor(Desc) */
62949 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
62950 "changed to an accessor, delete arguments binding"));
62951
62952 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
62953 } else {
62954 /* Note: this order matters (final value before deleting map entry must be done) */
62955 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
62956 "check for value update / binding deletion"));
62957
62958 if (has_value) {
62959 duk_hstring *varname;
62960
62961 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
62962 "update bound value (variable/argument)"));
62963
62964 varname = duk_require_hstring(thr, -1);
62965 DUK_ASSERT(varname != NULL);
62966
62967 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
62968 "key=%!O, varname=%!O, value=%!T",
62969 (duk_heaphdr *) key,
62970 (duk_heaphdr *) varname,
62971 (duk_tval *) duk_require_tval(thr, idx_value)));
62972
62973 /* strict flag for putvar comes from our caller (currently: fixed) */
62974 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/);
62975 }
62976 if (has_writable && !is_writable) {
62977 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
62978 "changed to non-writable, delete arguments binding"));
62979
62980 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
62981 }
62982 }
62983
62984 /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
62985 * but this doesn't matter now.
62986 */
62987 }
62988
62989 success_no_exotics:
62990 /* Some code paths use NORZ macros for simplicity, ensure refzero
62991 * handling is completed.
62992 */
62993 DUK_REFZERO_CHECK_SLOW(thr);
62994 return 1;
62995
62996 fail_not_extensible:
62997 if (throw_flag) {
62998 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
62999 DUK_WO_NORETURN(return 0;);
63000 }
63001 return 0;
63002
63003 fail_virtual: /* just use the same "not configurable" error message" */
63004 fail_not_configurable:
63005 if (throw_flag) {
63006 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
63007 DUK_WO_NORETURN(return 0;);
63008 }
63009 return 0;
63010}
63011
63012/*
63013 * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
63014 */
63015
63016DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) {
63017 duk_hstring *h_v;
63018 duk_hobject *h_obj;
63019 duk_propdesc desc;
63020 duk_bool_t ret;
63021
63022 /* coercion order matters */
63023 h_v = duk_to_hstring_acceptsymbol(thr, 0);
63024 DUK_ASSERT(h_v != NULL);
63025
63026 h_obj = duk_push_this_coercible_to_object(thr);
63027 DUK_ASSERT(h_obj != NULL);
63028
63029 ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
63030
63031 duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
63032 return 1;
63033}
63034
63035/*
63036 * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9)
63037 *
63038 * Since the algorithms are similar, a helper provides both functions.
63039 * Freezing is essentially sealing + making plain properties non-writable.
63040 *
63041 * Note: virtual (non-concrete) properties which are non-configurable but
63042 * writable would pose some problems, but such properties do not currently
63043 * exist (all virtual properties are non-configurable and non-writable).
63044 * If they did exist, the non-configurability does NOT prevent them from
63045 * becoming non-writable. However, this change should be recorded somehow
63046 * so that it would turn up (e.g. when getting the property descriptor),
63047 * requiring some additional flags in the object.
63048 */
63049
63050DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
63051 duk_uint_fast32_t i;
63052
63053 DUK_ASSERT(thr != NULL);
63054 DUK_ASSERT(thr->heap != NULL);
63055 DUK_ASSERT(obj != NULL);
63056
63057 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
63058
63059#if defined(DUK_USE_ROM_OBJECTS)
63060 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
63061 DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
63062 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
63063 DUK_WO_NORETURN(return;);
63064 }
63065#endif
63066
63067 /*
63068 * Abandon array part because all properties must become non-configurable.
63069 * Note that this is now done regardless of whether this is always the case
63070 * (skips check, but performance problem if caller would do this many times
63071 * for the same object; not likely).
63072 */
63073
63074 duk__abandon_array_part(thr, obj);
63075 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
63076
63077 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
63078 duk_uint8_t *fp;
63079
63080 /* since duk__abandon_array_part() causes a resize, there should be no gaps in keys */
63081 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
63082
63083 /* avoid multiple computations of flags address; bypasses macros */
63084 fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
63085 if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
63086 *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
63087 } else {
63088 *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
63089 }
63090 }
63091
63092 DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
63093
63094 /* no need to compact since we already did that in duk__abandon_array_part()
63095 * (regardless of whether an array part existed or not.
63096 */
63097
63098 return;
63099}
63100
63101/*
63102 * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
63103 *
63104 * Since the algorithms are similar, a helper provides both functions.
63105 * Freezing is essentially sealing + making plain properties non-writable.
63106 *
63107 * Note: all virtual (non-concrete) properties are currently non-configurable
63108 * and non-writable (and there are no accessor virtual properties), so they don't
63109 * need to be considered here now.
63110 */
63111
63112DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
63113 duk_uint_fast32_t i;
63114
63115 DUK_ASSERT(obj != NULL);
63116 DUK_UNREF(thr);
63117
63118 /* Note: no allocation pressure, no need to check refcounts etc */
63119
63120 /* must not be extensible */
63121 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
63122 return 0;
63123 }
63124
63125 /* all virtual properties are non-configurable and non-writable */
63126
63127 /* entry part must not contain any configurable properties, or
63128 * writable properties (if is_frozen).
63129 */
63130 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
63131 duk_small_uint_t flags;
63132
63133 if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
63134 continue;
63135 }
63136
63137 /* avoid multiple computations of flags address; bypasses macros */
63138 flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
63139
63140 if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
63141 return 0;
63142 }
63143 if (is_frozen &&
63144 !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
63145 (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
63146 return 0;
63147 }
63148 }
63149
63150 /* array part must not contain any non-unused properties, as they would
63151 * be configurable and writable.
63152 */
63153 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
63154 duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
63155 if (!DUK_TVAL_IS_UNUSED(tv)) {
63156 return 0;
63157 }
63158 }
63159
63160 return 1;
63161}
63162
63163/*
63164 * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13)
63165 *
63166 * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
63167 * and the Object built-in bindings.
63168 */
63169
63170/* automatic undefs */
63171#undef DUK__HASH_DELETED
63172#undef DUK__HASH_UNUSED
63173#undef DUK__NO_ARRAY_INDEX
63174#undef DUK__VALSTACK_PROXY_LOOKUP
63175#undef DUK__VALSTACK_SPACE
63176#line 1 "duk_hstring_assert.c"
63177/*
63178 * duk_hstring assertion helpers.
63179 */
63180
63181/* #include duk_internal.h -> already included */
63182
63183#if defined(DUK_USE_ASSERTIONS)
63184
63185DUK_INTERNAL void duk_hstring_assert_valid(duk_hstring *h) {
63186 DUK_ASSERT(h != NULL);
63187}
63188
63189#endif /* DUK_USE_ASSERTIONS */
63190#line 1 "duk_hstring_misc.c"
63191/*
63192 * Misc support functions
63193 */
63194
63195/* #include duk_internal.h -> already included */
63196
63197/*
63198 * duk_hstring charCodeAt, with and without surrogate awareness
63199 */
63200
63201DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) {
63202 duk_uint32_t boff;
63203 const duk_uint8_t *p, *p_start, *p_end;
63204 duk_ucodepoint_t cp1;
63205 duk_ucodepoint_t cp2;
63206
63207 /* Caller must check character offset to be inside the string. */
63208 DUK_ASSERT(thr != NULL);
63209 DUK_ASSERT(h != NULL);
63210 DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
63211 DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
63212
63213 boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
63214 DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
63215 (long) pos, (long) boff, (duk_heaphdr *) h));
63216 DUK_ASSERT_DISABLE(boff >= 0);
63217 DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
63218
63219 p_start = DUK_HSTRING_GET_DATA(h);
63220 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
63221 p = p_start + boff;
63222 DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
63223 (const void *) p_start, (const void *) p_end,
63224 (const void *) p));
63225
63226 /* For invalid UTF-8 (never happens for standard ECMAScript strings)
63227 * return U+FFFD replacement character.
63228 */
63229 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) {
63230 if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) {
63231 /* The decode helper is memory safe even if 'cp1' was
63232 * decoded at the end of the string and 'p' is no longer
63233 * within string memory range.
63234 */
63235 cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */
63236 (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2);
63237 if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) {
63238 cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL);
63239 }
63240 }
63241 } else {
63242 cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
63243 }
63244
63245 return cp1;
63246}
63247
63248/*
63249 * duk_hstring charlen, when lazy charlen disabled
63250 */
63251
63252#if !defined(DUK_USE_HSTRING_LAZY_CLEN)
63253#if !defined(DUK_USE_HSTRING_CLEN)
63254#error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set
63255#endif
63256DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) {
63257 duk_uint32_t clen;
63258
63259 DUK_ASSERT(h != NULL);
63260 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h));
63261 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
63262
63263 clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
63264#if defined(DUK_USE_STRLEN16)
63265 DUK_ASSERT(clen <= 0xffffUL); /* Bytelength checked during interning. */
63266 h->clen16 = (duk_uint16_t) clen;
63267#else
63268 h->clen = (duk_uint32_t) clen;
63269#endif
63270 if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) {
63271 DUK_HSTRING_SET_ASCII(h);
63272 }
63273}
63274
63275DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
63276#if defined(DUK_USE_STRLEN16)
63277 return h->clen16;
63278#else
63279 return h->clen;
63280#endif
63281}
63282#endif /* !DUK_USE_HSTRING_LAZY_CLEN */
63283
63284/*
63285 * duk_hstring charlen, when lazy charlen enabled
63286 */
63287
63288#if defined(DUK_USE_HSTRING_LAZY_CLEN)
63289#if defined(DUK_USE_HSTRING_CLEN)
63290DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
63291 duk_size_t res;
63292
63293 DUK_ASSERT(h->clen == 0); /* Checked by caller. */
63294
63295#if defined(DUK_USE_ROM_STRINGS)
63296 /* ROM strings have precomputed clen, but if the computed clen is zero
63297 * we can still come here and can't write anything.
63298 */
63299 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
63300 return 0;
63301 }
63302#endif
63303
63304 res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
63305#if defined(DUK_USE_STRLEN16)
63306 DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */
63307 h->clen16 = (duk_uint16_t) res;
63308#else
63309 h->clen = (duk_uint32_t) res;
63310#endif
63311 if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
63312 DUK_HSTRING_SET_ASCII(h);
63313 }
63314 return res;
63315}
63316#else /* DUK_USE_HSTRING_CLEN */
63317DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
63318 if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) {
63319 /* Most practical strings will go here. */
63320 return DUK_HSTRING_GET_BYTELEN(h);
63321 } else {
63322 /* ASCII flag is lazy, so set it here. */
63323 duk_size_t res;
63324
63325 /* XXX: here we could use the strcache to speed up the
63326 * computation (matters for 'i < str.length' loops).
63327 */
63328
63329 res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
63330
63331#if defined(DUK_USE_ROM_STRINGS)
63332 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
63333 /* For ROM strings, can't write anything; ASCII flag
63334 * is preset so we don't need to update it.
63335 */
63336 return res;
63337 }
63338#endif
63339 if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
63340 DUK_HSTRING_SET_ASCII(h);
63341 }
63342 return res;
63343 }
63344}
63345#endif /* DUK_USE_HSTRING_CLEN */
63346
63347#if defined(DUK_USE_HSTRING_CLEN)
63348DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
63349#if defined(DUK_USE_STRLEN16)
63350 if (DUK_LIKELY(h->clen16 != 0)) {
63351 return h->clen16;
63352 }
63353#else
63354 if (DUK_LIKELY(h->clen != 0)) {
63355 return h->clen;
63356 }
63357#endif
63358 return duk__hstring_get_charlen_slowpath(h);
63359}
63360#else /* DUK_USE_HSTRING_CLEN */
63361DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
63362 /* Always use slow path. */
63363 return duk__hstring_get_charlen_slowpath(h);
63364}
63365#endif /* DUK_USE_HSTRING_CLEN */
63366#endif /* DUK_USE_HSTRING_LAZY_CLEN */
63367
63368/*
63369 * Compare duk_hstring to an ASCII cstring.
63370 */
63371
63372DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) {
63373 duk_size_t len;
63374
63375 DUK_ASSERT(h != NULL);
63376 DUK_ASSERT(cstr != NULL);
63377
63378 len = DUK_STRLEN(cstr);
63379 if (len != DUK_HSTRING_GET_BYTELEN(h)) {
63380 return 0;
63381 }
63382 if (duk_memcmp((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
63383 return 1;
63384 }
63385 return 0;
63386}
63387#line 1 "duk_hthread_alloc.c"
63388/*
63389 * duk_hthread allocation and freeing.
63390 */
63391
63392/* #include duk_internal.h -> already included */
63393
63394/*
63395 * Allocate initial stacks for a thread. Note that 'thr' must be reachable
63396 * as a garbage collection may be triggered by the allocation attempts.
63397 * Returns zero (without leaking memory) if init fails.
63398 */
63399
63400DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
63401 duk_size_t alloc_size;
63402 duk_size_t i;
63403
63404 DUK_ASSERT(heap != NULL);
63405 DUK_ASSERT(thr != NULL);
63406 DUK_ASSERT(thr->valstack == NULL);
63407 DUK_ASSERT(thr->valstack_end == NULL);
63408 DUK_ASSERT(thr->valstack_alloc_end == NULL);
63409 DUK_ASSERT(thr->valstack_bottom == NULL);
63410 DUK_ASSERT(thr->valstack_top == NULL);
63411 DUK_ASSERT(thr->callstack_curr == NULL);
63412
63413 /* valstack */
63414 DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE);
63415 alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
63416 thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
63417 if (!thr->valstack) {
63418 goto fail;
63419 }
63420 duk_memzero(thr->valstack, alloc_size);
63421 thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM;
63422 thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
63423 thr->valstack_bottom = thr->valstack;
63424 thr->valstack_top = thr->valstack;
63425
63426 for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
63427 DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
63428 }
63429
63430 return 1;
63431
63432 fail:
63433 DUK_FREE(heap, thr->valstack);
63434 DUK_ASSERT(thr->callstack_curr == NULL);
63435
63436 thr->valstack = NULL;
63437 return 0;
63438}
63439
63440/* For indirect allocs. */
63441
63442DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
63443 duk_hthread *thr = (duk_hthread *) ud;
63444 DUK_UNREF(heap);
63445 return (void *) thr->valstack;
63446}
63447#line 1 "duk_hthread_builtins.c"
63448/*
63449 * Initialize built-in objects. Current thread must have a valstack
63450 * and initialization errors may longjmp, so a setjmp() catch point
63451 * must exist.
63452 */
63453
63454/* #include duk_internal.h -> already included */
63455
63456/*
63457 * Encoding constants, must match genbuiltins.py
63458 */
63459
63460#define DUK__PROP_FLAGS_BITS 3
63461#define DUK__LENGTH_PROP_BITS 3
63462#define DUK__NARGS_BITS 3
63463#define DUK__PROP_TYPE_BITS 3
63464
63465#define DUK__NARGS_VARARGS_MARKER 0x07
63466
63467#define DUK__PROP_TYPE_DOUBLE 0
63468#define DUK__PROP_TYPE_STRING 1
63469#define DUK__PROP_TYPE_STRIDX 2
63470#define DUK__PROP_TYPE_BUILTIN 3
63471#define DUK__PROP_TYPE_UNDEFINED 4
63472#define DUK__PROP_TYPE_BOOLEAN_TRUE 5
63473#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
63474#define DUK__PROP_TYPE_ACCESSOR 7
63475
63476/*
63477 * Create built-in objects by parsing an init bitstream generated
63478 * by genbuiltins.py.
63479 */
63480
63481#if defined(DUK_USE_ROM_OBJECTS)
63482#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
63483DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
63484 duk_hobject *h_global;
63485#if defined(DUK_USE_ROM_GLOBAL_CLONE)
63486 duk_hobject *h_oldglobal;
63487 duk_uint8_t *props;
63488 duk_size_t alloc_size;
63489#endif
63490 duk_hobject *h_objenv;
63491
63492 /* XXX: refactor into internal helper, duk_clone_hobject() */
63493
63494#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
63495 /* Inherit from ROM-based global object: less RAM usage, less transparent. */
63496 h_global = duk_push_object_helper(thr,
63497 DUK_HOBJECT_FLAG_EXTENSIBLE |
63498 DUK_HOBJECT_FLAG_FASTREFS |
63499 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
63500 DUK_BIDX_GLOBAL);
63501 DUK_ASSERT(h_global != NULL);
63502#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
63503 /* Clone the properties of the ROM-based global object to create a
63504 * fully RAM-based global object. Uses more memory than the inherit
63505 * model but more compliant.
63506 */
63507 h_global = duk_push_object_helper(thr,
63508 DUK_HOBJECT_FLAG_EXTENSIBLE |
63509 DUK_HOBJECT_FLAG_FASTREFS |
63510 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
63511 DUK_BIDX_OBJECT_PROTOTYPE);
63512 DUK_ASSERT(h_global != NULL);
63513 h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL];
63514 DUK_ASSERT(h_oldglobal != NULL);
63515
63516 /* Copy the property table verbatim; this handles attributes etc.
63517 * For ROM objects it's not necessary (or possible) to update
63518 * refcounts so leave them as is.
63519 */
63520 alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal);
63521 DUK_ASSERT(alloc_size > 0);
63522 props = DUK_ALLOC_CHECKED(thr, alloc_size);
63523 DUK_ASSERT(props != NULL);
63524 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL);
63525 duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);
63526
63527 /* XXX: keep property attributes or tweak them here?
63528 * Properties will now be non-configurable even when they're
63529 * normally configurable for the global object.
63530 */
63531
63532 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL);
63533 DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props);
63534 DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal));
63535 DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal));
63536 DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal));
63537 DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal));
63538#else
63539#error internal error in config defines
63540#endif
63541
63542 duk_hobject_compact_props(thr, h_global);
63543 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
63544 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */
63545 thr->builtins[DUK_BIDX_GLOBAL] = h_global;
63546 DUK_HOBJECT_INCREF(thr, h_global);
63547 DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global));
63548
63549 /* Create a fresh object environment for the global scope. This is
63550 * needed so that the global scope points to the newly created RAM-based
63551 * global object.
63552 */
63553 h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr,
63554 DUK_HOBJECT_FLAG_EXTENSIBLE |
63555 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
63556 DUK_ASSERT(h_objenv != NULL);
63557 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL);
63558 duk_push_hobject(thr, h_objenv);
63559
63560 DUK_ASSERT(h_global != NULL);
63561 ((duk_hobjenv *) h_objenv)->target = h_global;
63562 DUK_HOBJECT_INCREF(thr, h_global);
63563 DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0);
63564
63565 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
63566 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */
63567 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv;
63568 DUK_HOBJECT_INCREF(thr, h_objenv);
63569 DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv));
63570
63571 DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_objenv);
63572
63573 duk_pop_2(thr); /* Pop global object and global env. */
63574}
63575#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
63576
63577DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
63578 /* Setup builtins from ROM objects. All heaps/threads will share
63579 * the same readonly objects.
63580 */
63581 duk_small_uint_t i;
63582
63583 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
63584 duk_hobject *h;
63585 h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
63586 DUK_ASSERT(h != NULL);
63587 thr->builtins[i] = h;
63588 }
63589
63590#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
63591 /* By default the global object is read-only which is often much
63592 * more of an issue than having read-only built-in objects (like
63593 * RegExp, Date, etc). Use a RAM-based copy of the global object
63594 * and the global environment object for convenience.
63595 */
63596 duk__duplicate_ram_global_object(thr);
63597#endif
63598}
63599#else /* DUK_USE_ROM_OBJECTS */
63600DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
63601 duk_small_uint_t n;
63602
63603 n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63604 DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
63605 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
63606 duk_push_hstring_stridx(thr, n);
63607}
63608DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
63609 /* XXX: built-ins data could provide a maximum length that is
63610 * actually needed; bitpacked max length is now 256 bytes.
63611 */
63612 duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN];
63613 duk_small_uint_t len;
63614
63615 len = duk_bd_decode_bitpacked_string(bd, tmp);
63616 duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len);
63617}
63618DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
63619 duk_small_uint_t n;
63620
63621 n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63622 if (n == 0) {
63623 duk__push_string(thr, bd);
63624 } else {
63625 n--;
63626 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
63627 duk_push_hstring_stridx(thr, n);
63628 }
63629}
63630DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
63631 duk_double_union du;
63632 duk_small_uint_t i;
63633
63634 for (i = 0; i < 8; i++) {
63635 /* Encoding endianness must match target memory layout,
63636 * build scripts and genbuiltins.py must ensure this.
63637 */
63638 du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
63639 }
63640
63641 duk_push_number(thr, du.d); /* push operation normalizes NaNs */
63642}
63643
63644DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
63645 duk_bitdecoder_ctx bd_ctx;
63646 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
63647 duk_hobject *h;
63648 duk_small_uint_t i, j;
63649
63650 DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
63651
63652 duk_memzero(&bd_ctx, sizeof(bd_ctx));
63653 bd->data = (const duk_uint8_t *) duk_builtins_data;
63654 bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
63655
63656 /*
63657 * First create all built-in bare objects on the empty valstack.
63658 *
63659 * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
63660 * stack indices matching their eventual thr->builtins[] index.
63661 *
63662 * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
63663 * will exist on the value stack during init but won't be placed
63664 * into thr->builtins[]. These are objects referenced in some way
63665 * from thr->builtins[] roots but which don't need to be indexed by
63666 * Duktape through thr->builtins[] (e.g. user custom objects).
63667 *
63668 * Internal prototypes will be incorrect (NULL) at this stage.
63669 */
63670
63671 duk_require_stack(thr, DUK_NUM_ALL_BUILTINS);
63672
63673 DUK_DD(DUK_DDPRINT("create empty built-ins"));
63674 DUK_ASSERT_TOP(thr, 0);
63675 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
63676 duk_small_uint_t class_num;
63677 duk_small_int_t len = -1; /* must be signed */
63678
63679 class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63680 len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
63681
63682 if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
63683 duk_small_uint_t natidx;
63684 duk_small_int_t c_nargs; /* must hold DUK_VARARGS */
63685 duk_c_function c_func;
63686 duk_int16_t magic;
63687
63688 DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
63689 DUK_ASSERT(len >= 0);
63690
63691 natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63692 DUK_ASSERT(natidx != 0);
63693 c_func = duk_bi_native_functions[natidx];
63694 DUK_ASSERT(c_func != NULL);
63695
63696 c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/);
63697 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
63698 c_nargs = DUK_VARARGS;
63699 }
63700
63701 /* XXX: set magic directly here? (it could share the c_nargs arg) */
63702 (void) duk_push_c_function_builtin(thr, c_func, c_nargs);
63703 h = duk_known_hobject(thr, -1);
63704
63705 /* Currently all built-in native functions are strict.
63706 * duk_push_c_function() now sets strict flag, so
63707 * assert for it.
63708 */
63709 DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
63710
63711 /* XXX: function properties */
63712
63713 duk__push_stridx_or_string(thr, bd);
63714#if defined(DUK_USE_FUNC_NAME_PROPERTY)
63715 duk_xdef_prop_stridx_short(thr,
63716 -2,
63717 DUK_STRIDX_NAME,
63718 DUK_PROPDESC_FLAGS_C);
63719#else
63720 duk_pop(thr); /* Not very ideal but good enough for now. */
63721#endif
63722
63723 /* Almost all global level Function objects are constructable
63724 * but not all: Function.prototype is a non-constructable,
63725 * callable Function.
63726 */
63727 if (duk_bd_decode_flag(bd)) {
63728 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
63729 } else {
63730 DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
63731 }
63732
63733 /* Cast converts magic to 16-bit signed value */
63734 magic = (duk_int16_t) duk_bd_decode_varuint(bd);
63735 ((duk_hnatfunc *) h)->magic = magic;
63736 } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
63737 duk_push_array(thr);
63738 } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) {
63739 duk_hobjenv *env;
63740 duk_hobject *global;
63741
63742 DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV);
63743 DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL);
63744
63745 env = duk_hobjenv_alloc(thr,
63746 DUK_HOBJECT_FLAG_EXTENSIBLE |
63747 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
63748 DUK_ASSERT(env->target == NULL);
63749 duk_push_hobject(thr, (duk_hobject *) env);
63750
63751 global = duk_known_hobject(thr, DUK_BIDX_GLOBAL);
63752 DUK_ASSERT(global != NULL);
63753 env->target = global;
63754 DUK_HOBJECT_INCREF(thr, global);
63755 DUK_ASSERT(env->has_this == 0);
63756
63757 DUK_HOBJENV_ASSERT_VALID(env);
63758 } else {
63759 DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV);
63760
63761 (void) duk_push_object_helper(thr,
63762 DUK_HOBJECT_FLAG_FASTREFS |
63763 DUK_HOBJECT_FLAG_EXTENSIBLE,
63764 -1); /* no prototype or class yet */
63765
63766 }
63767
63768 h = duk_known_hobject(thr, -1);
63769 DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
63770
63771 if (i < DUK_NUM_BUILTINS) {
63772 thr->builtins[i] = h;
63773 DUK_HOBJECT_INCREF(thr, &h->hdr);
63774 }
63775
63776 if (len >= 0) {
63777 /* In ES2015+ built-in function object .length property
63778 * has property attributes C (configurable only):
63779 * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects
63780 *
63781 * Array.prototype remains an Array instance in ES2015+
63782 * and its length has attributes W (writable only).
63783 * Because .length is now virtual for duk_harray, it is
63784 * not encoded explicitly in init data.
63785 */
63786
63787 DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */
63788 duk_push_int(thr, len);
63789 duk_xdef_prop_stridx_short(thr,
63790 -2,
63791 DUK_STRIDX_LENGTH,
63792 DUK_PROPDESC_FLAGS_C);
63793 }
63794
63795 /* enable exotic behaviors last */
63796
63797 if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
63798 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */
63799 }
63800 if (class_num == DUK_HOBJECT_CLASS_STRING) {
63801 DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
63802 }
63803
63804 /* some assertions */
63805
63806 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
63807 /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
63808 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h));
63809 DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h));
63810 /* DUK_HOBJECT_FLAG_NATFUNC varies */
63811 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h));
63812 DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(h));
63813 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY);
63814 /* DUK_HOBJECT_FLAG_STRICT varies */
63815 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */
63816 DUK_HOBJECT_HAS_NEWENV(h));
63817 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
63818 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
63819 /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
63820 /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
63821 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
63822
63823 DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
63824 }
63825
63826 /*
63827 * Then decode the builtins init data (see genbuiltins.py) to
63828 * init objects. Internal prototypes are set at this stage,
63829 * with thr->builtins[] populated.
63830 */
63831
63832 DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
63833 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
63834 duk_small_uint_t t;
63835 duk_small_uint_t num;
63836
63837 DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
63838 h = duk_known_hobject(thr, (duk_idx_t) i);
63839
63840 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63841 if (t > 0) {
63842 t--;
63843 DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
63844 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t));
63845 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
63846 /* Standard native built-ins cannot inherit from
63847 * %NativeFunctionPrototype%, they are required to
63848 * inherit from Function.prototype directly.
63849 */
63850 DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL);
63851 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
63852 }
63853
63854 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63855 if (t > 0) {
63856 /* 'prototype' property for all built-in objects (which have it) has attributes:
63857 * [[Writable]] = false,
63858 * [[Enumerable]] = false,
63859 * [[Configurable]] = false
63860 */
63861 t--;
63862 DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
63863 duk_dup(thr, (duk_idx_t) t);
63864 duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE);
63865 }
63866
63867 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63868 if (t > 0) {
63869 /* 'constructor' property for all built-in objects (which have it) has attributes:
63870 * [[Writable]] = true,
63871 * [[Enumerable]] = false,
63872 * [[Configurable]] = true
63873 */
63874 t--;
63875 DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
63876 duk_dup(thr, (duk_idx_t) t);
63877 duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);
63878 }
63879
63880 /* normal valued properties */
63881 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63882 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
63883 for (j = 0; j < num; j++) {
63884 duk_small_uint_t defprop_flags;
63885
63886 duk__push_stridx_or_string(thr, bd);
63887
63888 /*
63889 * Property attribute defaults are defined in E5 Section 15 (first
63890 * few pages); there is a default for all properties and a special
63891 * default for 'length' properties. Variation from the defaults is
63892 * signaled using a single flag bit in the bitstream.
63893 */
63894
63895 defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
63896 DUK__PROP_FLAGS_BITS,
63897 (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
63898 defprop_flags |= DUK_DEFPROP_FORCE |
63899 DUK_DEFPROP_HAVE_VALUE |
63900 DUK_DEFPROP_HAVE_WRITABLE |
63901 DUK_DEFPROP_HAVE_ENUMERABLE |
63902 DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */
63903
63904 /* The writable, enumerable, configurable flags in prop_flags
63905 * match both duk_def_prop() and internal property flags.
63906 */
63907 DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
63908 DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
63909 DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
63910
63911 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
63912
63913 DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
63914 (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t));
63915
63916 switch (t) {
63917 case DUK__PROP_TYPE_DOUBLE: {
63918 duk__push_double(thr, bd);
63919 break;
63920 }
63921 case DUK__PROP_TYPE_STRING: {
63922 duk__push_string(thr, bd);
63923 break;
63924 }
63925 case DUK__PROP_TYPE_STRIDX: {
63926 duk__push_stridx(thr, bd);
63927 break;
63928 }
63929 case DUK__PROP_TYPE_BUILTIN: {
63930 duk_small_uint_t bidx;
63931
63932 bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63933 duk_dup(thr, (duk_idx_t) bidx);
63934 break;
63935 }
63936 case DUK__PROP_TYPE_UNDEFINED: {
63937 duk_push_undefined(thr);
63938 break;
63939 }
63940 case DUK__PROP_TYPE_BOOLEAN_TRUE: {
63941 duk_push_true(thr);
63942 break;
63943 }
63944 case DUK__PROP_TYPE_BOOLEAN_FALSE: {
63945 duk_push_false(thr);
63946 break;
63947 }
63948 case DUK__PROP_TYPE_ACCESSOR: {
63949 duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63950 duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63951 duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63952 duk_c_function c_func_getter;
63953 duk_c_function c_func_setter;
63954
63955 DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
63956 (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
63957
63958 c_func_getter = duk_bi_native_functions[natidx_getter];
63959 if (c_func_getter != NULL) {
63960 duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */
63961 duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
63962 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
63963 }
63964 c_func_setter = duk_bi_native_functions[natidx_setter];
63965 if (c_func_setter != NULL) {
63966 duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */
63967 duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
63968 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
63969 }
63970
63971 /* Writable flag doesn't make sense for an accessor. */
63972 DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
63973
63974 defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
63975 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
63976 break;
63977 }
63978 default: {
63979 /* exhaustive */
63980 DUK_UNREACHABLE();
63981 }
63982 }
63983
63984 duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
63985 DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS);
63986 }
63987
63988 /* native function properties */
63989 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
63990 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
63991 for (j = 0; j < num; j++) {
63992 duk_hstring *h_key;
63993 duk_small_uint_t natidx;
63994 duk_int_t c_nargs; /* must hold DUK_VARARGS */
63995 duk_small_uint_t c_length;
63996 duk_int16_t magic;
63997 duk_c_function c_func;
63998 duk_hnatfunc *h_func;
63999#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
64000 duk_small_int_t lightfunc_eligible;
64001#endif
64002 duk_small_uint_t defprop_flags;
64003
64004 duk__push_stridx_or_string(thr, bd);
64005 h_key = duk_known_hstring(thr, -1);
64006 DUK_UNREF(h_key);
64007 natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
64008
64009 c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
64010 c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/);
64011 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
64012 c_nargs = DUK_VARARGS;
64013 }
64014
64015 c_func = duk_bi_native_functions[natidx];
64016
64017 DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
64018 (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
64019 (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
64020
64021 /* Cast converts magic to 16-bit signed value */
64022 magic = (duk_int16_t) duk_bd_decode_varuint(bd);
64023
64024#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
64025 lightfunc_eligible =
64026 ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
64027 (c_length <= DUK_LFUNC_LENGTH_MAX) &&
64028 (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
64029
64030 /* These functions have trouble working as lightfuncs.
64031 * Some of them have specific asserts and some may have
64032 * additional properties (e.g. 'require.id' may be written).
64033 */
64034 if (c_func == duk_bi_global_object_eval) {
64035 lightfunc_eligible = 0;
64036 }
64037#if defined(DUK_USE_COROUTINE_SUPPORT)
64038 if (c_func == duk_bi_thread_yield ||
64039 c_func == duk_bi_thread_resume) {
64040 lightfunc_eligible = 0;
64041 }
64042#endif
64043 if (c_func == duk_bi_function_prototype_call ||
64044 c_func == duk_bi_function_prototype_apply ||
64045 c_func == duk_bi_reflect_apply ||
64046 c_func == duk_bi_reflect_construct) {
64047 lightfunc_eligible = 0;
64048 }
64049
64050 if (lightfunc_eligible) {
64051 duk_tval tv_lfunc;
64052 duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
64053 duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
64054 DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
64055 duk_push_tval(thr, &tv_lfunc);
64056 DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(thr, -1)));
64057 goto lightfunc_skip;
64058 }
64059
64060 DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic));
64061#endif /* DUK_USE_LIGHTFUNC_BUILTINS */
64062
64063 /* [ (builtin objects) name ] */
64064
64065 duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs);
64066 h_func = duk_known_hnatfunc(thr, -1);
64067 DUK_UNREF(h_func);
64068
64069 /* XXX: add into init data? */
64070
64071 /* Special call handling, not described in init data. */
64072 if (c_func == duk_bi_global_object_eval ||
64073 c_func == duk_bi_function_prototype_call ||
64074 c_func == duk_bi_function_prototype_apply ||
64075 c_func == duk_bi_reflect_apply ||
64076 c_func == duk_bi_reflect_construct) {
64077 DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func);
64078 }
64079
64080 /* Currently all built-in native functions are strict.
64081 * This doesn't matter for many functions, but e.g.
64082 * String.prototype.charAt (and other string functions)
64083 * rely on being strict so that their 'this' binding is
64084 * not automatically coerced.
64085 */
64086 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
64087
64088 /* No built-in functions are constructable except the top
64089 * level ones (Number, etc).
64090 */
64091 DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
64092
64093 /* XXX: any way to avoid decoding magic bit; there are quite
64094 * many function properties and relatively few with magic values.
64095 */
64096 h_func->magic = magic;
64097
64098 /* [ (builtin objects) name func ] */
64099
64100 duk_push_uint(thr, c_length);
64101 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
64102
64103 duk_dup_m2(thr);
64104 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
64105
64106 /* XXX: other properties of function instances; 'arguments', 'caller'. */
64107
64108 DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
64109 (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1)));
64110
64111 /* [ (builtin objects) name func ] */
64112
64113 /*
64114 * The default property attributes are correct for all
64115 * function valued properties of built-in objects now.
64116 */
64117
64118#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
64119 lightfunc_skip:
64120#endif
64121
64122 defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
64123 DUK__PROP_FLAGS_BITS,
64124 (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
64125 defprop_flags |= DUK_DEFPROP_FORCE |
64126 DUK_DEFPROP_HAVE_VALUE |
64127 DUK_DEFPROP_HAVE_WRITABLE |
64128 DUK_DEFPROP_HAVE_ENUMERABLE |
64129 DUK_DEFPROP_HAVE_CONFIGURABLE;
64130 DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
64131 DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
64132 DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
64133
64134 duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
64135
64136 /* [ (builtin objects) ] */
64137 }
64138 }
64139
64140 /*
64141 * Special post-tweaks, for cases not covered by the init data format.
64142 *
64143 * - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
64144 * toGMTString is required to have the same Function object as
64145 * toUTCString in E5 Section B.2.6. Note that while Smjs respects
64146 * this, V8 does not (the Function objects are distinct).
64147 *
64148 * - Make DoubleError non-extensible.
64149 *
64150 * - Add info about most important effective compile options to Duktape.
64151 *
64152 * - Possibly remove some properties (values or methods) which are not
64153 * desirable with current feature options but are not currently
64154 * conditional in init data.
64155 */
64156
64157#if defined(DUK_USE_DATE_BUILTIN)
64158 duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
64159 duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
64160#endif
64161
64162 h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
64163 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
64164
64165#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
64166 DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
64167 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
64168#endif
64169
64170#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
64171 DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
64172 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
64173#endif
64174
64175 /* XXX: relocate */
64176 duk_push_string(thr,
64177 /* Endianness indicator */
64178#if defined(DUK_USE_INTEGER_LE)
64179 "l"
64180#elif defined(DUK_USE_INTEGER_BE)
64181 "b"
64182#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
64183 "m"
64184#else
64185 "?"
64186#endif
64187#if defined(DUK_USE_DOUBLE_LE)
64188 "l"
64189#elif defined(DUK_USE_DOUBLE_BE)
64190 "b"
64191#elif defined(DUK_USE_DOUBLE_ME)
64192 "m"
64193#else
64194 "?"
64195#endif
64196 " "
64197 /* Packed or unpacked tval */
64198#if defined(DUK_USE_PACKED_TVAL)
64199 "p"
64200#else
64201 "u"
64202#endif
64203#if defined(DUK_USE_FASTINT)
64204 "f"
64205#endif
64206 " "
64207 /* Low memory/performance options */
64208#if defined(DUK_USE_STRTAB_PTRCOMP)
64209 "s"
64210#endif
64211#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
64212 "n"
64213#endif
64214#if defined(DUK_USE_HEAPPTR16)
64215 "h"
64216#endif
64217#if defined(DUK_USE_DATAPTR16)
64218 "d"
64219#endif
64220#if defined(DUK_USE_FUNCPTR16)
64221 "f"
64222#endif
64223#if defined(DUK_USE_REFCOUNT16)
64224 "R"
64225#endif
64226#if defined(DUK_USE_STRHASH16)
64227 "H"
64228#endif
64229#if defined(DUK_USE_STRLEN16)
64230 "S"
64231#endif
64232#if defined(DUK_USE_BUFLEN16)
64233 "B"
64234#endif
64235#if defined(DUK_USE_OBJSIZES16)
64236 "O"
64237#endif
64238#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
64239 "L"
64240#endif
64241#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
64242 /* XXX: This won't be shown in practice now
64243 * because this code is not run when builtins
64244 * are in ROM.
64245 */
64246 "Z"
64247#endif
64248#if defined(DUK_USE_LITCACHE_SIZE)
64249 "l"
64250#endif
64251 " "
64252 /* Object property allocation layout */
64253#if defined(DUK_USE_HOBJECT_LAYOUT_1)
64254 "p1"
64255#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
64256 "p2"
64257#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
64258 "p3"
64259#else
64260 "p?"
64261#endif
64262 " "
64263 /* Alignment guarantee */
64264#if (DUK_USE_ALIGN_BY == 4)
64265 "a4"
64266#elif (DUK_USE_ALIGN_BY == 8)
64267 "a8"
64268#elif (DUK_USE_ALIGN_BY == 1)
64269 "a1"
64270#else
64271#error invalid DUK_USE_ALIGN_BY
64272#endif
64273 " "
64274 /* Architecture, OS, and compiler strings */
64275 DUK_USE_ARCH_STRING
64276 " "
64277 DUK_USE_OS_STRING
64278 " "
64279 DUK_USE_COMPILER_STRING);
64280 duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
64281
64282 /*
64283 * Since built-ins are not often extended, compact them.
64284 */
64285
64286 DUK_DD(DUK_DDPRINT("compact built-ins"));
64287 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
64288 duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i));
64289 }
64290
64291 DUK_D(DUK_DPRINT("INITBUILTINS END"));
64292
64293#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
64294 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
64295 DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
64296 (long) i, (duk_heaphdr *) duk_require_hobject(thr, (duk_idx_t) i)));
64297 }
64298#endif
64299
64300 /*
64301 * Pop built-ins from stack: they are now INCREF'd and
64302 * reachable from the builtins[] array or indirectly
64303 * through builtins[].
64304 */
64305
64306 duk_set_top(thr, 0);
64307 DUK_ASSERT_TOP(thr, 0);
64308}
64309#endif /* DUK_USE_ROM_OBJECTS */
64310
64311DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
64312 duk_small_uint_t i;
64313
64314 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
64315 thr_to->builtins[i] = thr_from->builtins[i];
64316 DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
64317 }
64318}
64319
64320/* automatic undefs */
64321#undef DUK__LENGTH_PROP_BITS
64322#undef DUK__NARGS_BITS
64323#undef DUK__NARGS_VARARGS_MARKER
64324#undef DUK__PROP_FLAGS_BITS
64325#undef DUK__PROP_TYPE_ACCESSOR
64326#undef DUK__PROP_TYPE_BITS
64327#undef DUK__PROP_TYPE_BOOLEAN_FALSE
64328#undef DUK__PROP_TYPE_BOOLEAN_TRUE
64329#undef DUK__PROP_TYPE_BUILTIN
64330#undef DUK__PROP_TYPE_DOUBLE
64331#undef DUK__PROP_TYPE_STRIDX
64332#undef DUK__PROP_TYPE_STRING
64333#undef DUK__PROP_TYPE_UNDEFINED
64334#line 1 "duk_hthread_misc.c"
64335/*
64336 * Thread support.
64337 */
64338
64339/* #include duk_internal.h -> already included */
64340
64341DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
64342 DUK_ASSERT(thr != NULL);
64343
64344 while (thr->callstack_curr != NULL) {
64345 duk_hthread_activation_unwind_norz(thr);
64346 }
64347
64348 thr->valstack_bottom = thr->valstack;
64349 duk_set_top(thr, 0); /* unwinds valstack, updating refcounts */
64350
64351 thr->state = DUK_HTHREAD_STATE_TERMINATED;
64352
64353 /* Here we could remove references to built-ins, but it may not be
64354 * worth the effort because built-ins are quite likely to be shared
64355 * with another (unterminated) thread, and terminated threads are also
64356 * usually garbage collected quite quickly.
64357 *
64358 * We could also shrink the value stack here, but that also may not
64359 * be worth the effort for the same reason.
64360 */
64361
64362 DUK_REFZERO_CHECK_SLOW(thr);
64363}
64364
64365#if defined(DUK_USE_DEBUGGER_SUPPORT)
64366DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
64367 duk_instr_t *bcode;
64368
64369 DUK_ASSERT(thr != NULL);
64370 DUK_ASSERT(act != NULL);
64371 DUK_UNREF(thr);
64372
64373 /* XXX: store 'bcode' pointer to activation for faster lookup? */
64374 if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
64375 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
64376 return (duk_uint_fast32_t) (act->curr_pc - bcode);
64377 }
64378 return 0;
64379}
64380#endif /* DUK_USE_DEBUGGER_SUPPORT */
64381
64382DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
64383 duk_instr_t *bcode;
64384 duk_uint_fast32_t ret;
64385
64386 DUK_ASSERT(thr != NULL);
64387 DUK_ASSERT(act != NULL);
64388 DUK_UNREF(thr);
64389
64390 if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
64391 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
64392 ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
64393 if (ret > 0) {
64394 ret--;
64395 }
64396 return ret;
64397 }
64398 return 0;
64399}
64400
64401/* Write bytecode executor's curr_pc back to topmost activation (if any). */
64402DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
64403 duk_activation *act;
64404
64405 DUK_ASSERT(thr != NULL);
64406
64407 if (thr->ptr_curr_pc != NULL) {
64408 /* ptr_curr_pc != NULL only when bytecode executor is active. */
64409 DUK_ASSERT(thr->callstack_top > 0);
64410 DUK_ASSERT(thr->callstack_curr != NULL);
64411 act = thr->callstack_curr;
64412 DUK_ASSERT(act != NULL);
64413 act->curr_pc = *thr->ptr_curr_pc;
64414 }
64415}
64416
64417DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
64418 duk_activation *act;
64419
64420 DUK_ASSERT(thr != NULL);
64421
64422 if (thr->ptr_curr_pc != NULL) {
64423 /* ptr_curr_pc != NULL only when bytecode executor is active. */
64424 DUK_ASSERT(thr->callstack_top > 0);
64425 DUK_ASSERT(thr->callstack_curr != NULL);
64426 act = thr->callstack_curr;
64427 DUK_ASSERT(act != NULL);
64428 act->curr_pc = *thr->ptr_curr_pc;
64429 thr->ptr_curr_pc = NULL;
64430 }
64431}
64432#line 1 "duk_hthread_stacks.c"
64433/*
64434 * Thread stack (mainly call stack) primitives: allocation of activations,
64435 * unwinding catchers and activations, etc.
64436 *
64437 * Value stack handling is a part of the API implementation.
64438 */
64439
64440/* #include duk_internal.h -> already included */
64441
64442/* Unwind the topmost catcher of the current activation (caller must check that
64443 * both exist) without side effects.
64444 */
64445DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) {
64446 duk_catcher *cat;
64447
64448 DUK_ASSERT(thr != NULL);
64449 DUK_ASSERT(act != NULL);
64450 DUK_ASSERT(act->cat != NULL); /* caller must check */
64451 cat = act->cat;
64452 DUK_ASSERT(cat != NULL);
64453
64454 DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)", (void *) cat));
64455
64456 if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
64457 duk_hobject *env;
64458
64459 env = act->lex_env; /* current lex_env of the activation (created for catcher) */
64460 DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
64461 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
64462 DUK_HOBJECT_INCREF(thr, act->lex_env);
64463 DUK_HOBJECT_DECREF_NORZ(thr, env);
64464
64465 /* There is no need to decref anything else than 'env': if 'env'
64466 * becomes unreachable, refzero will handle decref'ing its prototype.
64467 */
64468 }
64469
64470 act->cat = cat->parent;
64471 duk_hthread_catcher_free(thr, cat);
64472}
64473
64474/* Same as above, but caller is certain no catcher-related lexenv may exist. */
64475DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) {
64476 duk_catcher *cat;
64477
64478 DUK_ASSERT(thr != NULL);
64479 DUK_ASSERT(act != NULL);
64480 DUK_ASSERT(act->cat != NULL); /* caller must check */
64481 cat = act->cat;
64482 DUK_ASSERT(cat != NULL);
64483
64484 DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)", (void *) cat));
64485
64486 DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat));
64487
64488 act->cat = cat->parent;
64489 duk_hthread_catcher_free(thr, cat);
64490}
64491
64492DUK_LOCAL
64493#if defined(DUK_USE_CACHE_CATCHER)
64494DUK_NOINLINE
64495#endif
64496duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) {
64497 duk_catcher *cat;
64498
64499 cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher));
64500 DUK_ASSERT(cat != NULL);
64501 return cat;
64502}
64503
64504#if defined(DUK_USE_CACHE_CATCHER)
64505DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
64506 duk_catcher *cat;
64507
64508 DUK_ASSERT(thr != NULL);
64509
64510 cat = thr->heap->catcher_free;
64511 if (DUK_LIKELY(cat != NULL)) {
64512 thr->heap->catcher_free = cat->parent;
64513 return cat;
64514 }
64515
64516 return duk__hthread_catcher_alloc_slow(thr);
64517}
64518#else /* DUK_USE_CACHE_CATCHER */
64519DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
64520 return duk__hthread_catcher_alloc_slow(thr);
64521}
64522#endif /* DUK_USE_CACHE_CATCHER */
64523
64524DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) {
64525 DUK_ASSERT(thr != NULL);
64526 DUK_ASSERT(cat != NULL);
64527
64528#if defined(DUK_USE_CACHE_CATCHER)
64529 /* Unconditional caching for now; freed in mark-and-sweep. */
64530 cat->parent = thr->heap->catcher_free;
64531 thr->heap->catcher_free = cat;
64532#else
64533 DUK_FREE_CHECKED(thr, (void *) cat);
64534#endif
64535}
64536
64537DUK_LOCAL
64538#if defined(DUK_USE_CACHE_ACTIVATION)
64539DUK_NOINLINE
64540#endif
64541duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) {
64542 duk_activation *act;
64543
64544 act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation));
64545 DUK_ASSERT(act != NULL);
64546 return act;
64547}
64548
64549#if defined(DUK_USE_CACHE_ACTIVATION)
64550DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
64551 duk_activation *act;
64552
64553 DUK_ASSERT(thr != NULL);
64554
64555 act = thr->heap->activation_free;
64556 if (DUK_LIKELY(act != NULL)) {
64557 thr->heap->activation_free = act->parent;
64558 return act;
64559 }
64560
64561 return duk__hthread_activation_alloc_slow(thr);
64562}
64563#else /* DUK_USE_CACHE_ACTIVATION */
64564DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
64565 return duk__hthread_activation_alloc_slow(thr);
64566}
64567#endif /* DUK_USE_CACHE_ACTIVATION */
64568
64569
64570DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) {
64571 DUK_ASSERT(thr != NULL);
64572 DUK_ASSERT(act != NULL);
64573
64574#if defined(DUK_USE_CACHE_ACTIVATION)
64575 /* Unconditional caching for now; freed in mark-and-sweep. */
64576 act->parent = thr->heap->activation_free;
64577 thr->heap->activation_free = act;
64578#else
64579 DUK_FREE_CHECKED(thr, (void *) act);
64580#endif
64581}
64582
64583/* Internal helper: process the unwind for the topmost activation of a thread,
64584 * but leave the duk_activation in place for possible tailcall reuse.
64585 */
64586DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) {
64587#if defined(DUK_USE_DEBUGGER_SUPPORT)
64588 duk_heap *heap;
64589#endif
64590 duk_activation *act;
64591 duk_hobject *func;
64592 duk_hobject *tmp;
64593
64594 DUK_ASSERT(thr != NULL);
64595 DUK_ASSERT(thr->callstack_curr != NULL); /* caller must check */
64596 DUK_ASSERT(thr->callstack_top > 0);
64597 act = thr->callstack_curr;
64598 DUK_ASSERT(act != NULL);
64599 /* With lightfuncs, act 'func' may be NULL. */
64600
64601 /* With duk_activation records allocated separately, 'act' is a stable
64602 * pointer and not affected by side effects.
64603 */
64604
64605#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
64606 /*
64607 * Restore 'caller' property for non-strict callee functions.
64608 */
64609
64610 func = DUK_ACT_GET_FUNC(act);
64611 if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
64612 duk_tval *tv_caller;
64613 duk_tval tv_tmp;
64614 duk_hobject *h_tmp;
64615
64616 tv_caller = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, func, DUK_STRIDX_CALLER);
64617
64618 /* The act->prev_caller should only be set if the entry for 'caller'
64619 * exists (as it is only set in that case, and the property is not
64620 * configurable), but handle all the cases anyway.
64621 */
64622
64623 if (tv_caller) {
64624 DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
64625 if (act->prev_caller) {
64626 /* Just transfer the refcount from act->prev_caller to tv_caller,
64627 * so no need for a refcount update. This is the expected case.
64628 */
64629 DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
64630 act->prev_caller = NULL;
64631 } else {
64632 DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
64633 DUK_ASSERT(act->prev_caller == NULL);
64634 }
64635 DUK_TVAL_DECREF_NORZ(thr, &tv_tmp);
64636 } else {
64637 h_tmp = act->prev_caller;
64638 if (h_tmp) {
64639 act->prev_caller = NULL;
64640 DUK_HOBJECT_DECREF_NORZ(thr, h_tmp);
64641 }
64642 }
64643 DUK_ASSERT(act->prev_caller == NULL);
64644 }
64645#endif
64646
64647 /*
64648 * Unwind debugger state. If we unwind while stepping
64649 * (for any step type), pause execution. This is the
64650 * only place explicitly handling a step out.
64651 */
64652
64653#if defined(DUK_USE_DEBUGGER_SUPPORT)
64654 heap = thr->heap;
64655 if (heap->dbg_pause_act == thr->callstack_curr) {
64656 if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) {
64657 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit"));
64658 duk_debug_set_paused(heap);
64659 } else {
64660 DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL"));
64661 heap->dbg_pause_act = NULL; /* avoid stale pointers */
64662 }
64663 DUK_ASSERT(heap->dbg_pause_act == NULL);
64664 }
64665#endif
64666
64667 /*
64668 * Unwind catchers.
64669 *
64670 * Since there are no references in the catcher structure,
64671 * unwinding is quite simple. The only thing we need to
64672 * look out for is popping a possible lexical environment
64673 * established for an active catch clause.
64674 */
64675
64676 while (act->cat != NULL) {
64677 duk_hthread_catcher_unwind_norz(thr, act);
64678 }
64679
64680 /*
64681 * Close environment record(s) if they exist.
64682 *
64683 * Only variable environments are closed. If lex_env != var_env, it
64684 * cannot currently contain any register bound declarations.
64685 *
64686 * Only environments created for a NEWENV function are closed. If an
64687 * environment is created for e.g. an eval call, it must not be closed.
64688 */
64689
64690 func = DUK_ACT_GET_FUNC(act);
64691 if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
64692 DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
64693 goto skip_env_close;
64694 }
64695 /* func is NULL for lightfunc */
64696
64697 /* Catch sites are required to clean up their environments
64698 * in FINALLY part before propagating, so this should
64699 * always hold here.
64700 */
64701 DUK_ASSERT(act->lex_env == act->var_env);
64702
64703 /* XXX: Closing the environment record copies values from registers
64704 * into the scope object. It's side effect free as such, but may
64705 * currently run out of memory which causes an error throw. This is
64706 * an actual sandboxing problem for error unwinds, and needs to be
64707 * fixed e.g. by preallocating the scope property slots.
64708 */
64709 if (act->var_env != NULL) {
64710 DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
64711 (void *) act->var_env, (duk_heaphdr *) act->var_env));
64712 duk_js_close_environment_record(thr, act->var_env);
64713 }
64714
64715 skip_env_close:
64716
64717 /*
64718 * Update preventcount
64719 */
64720
64721 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
64722 DUK_ASSERT(thr->callstack_preventcount >= 1);
64723 thr->callstack_preventcount--;
64724 }
64725
64726 /*
64727 * Reference count updates, using NORZ macros so we don't
64728 * need to handle side effects.
64729 *
64730 * duk_activation pointers like act->var_env are intentionally
64731 * left as garbage and not NULLed. Without side effects they
64732 * can't be used when the values are dangling/garbage.
64733 */
64734
64735 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env);
64736 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env);
64737 tmp = DUK_ACT_GET_FUNC(act);
64738 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
64739 DUK_UNREF(tmp);
64740}
64741
64742/* Unwind topmost duk_activation of a thread, caller must ensure that an
64743 * activation exists. The call is side effect free, except that scope
64744 * closure may currently throw an out-of-memory error.
64745 */
64746DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) {
64747 duk_activation *act;
64748
64749 duk__activation_unwind_nofree_norz(thr);
64750
64751 DUK_ASSERT(thr->callstack_curr != NULL);
64752 DUK_ASSERT(thr->callstack_top > 0);
64753 act = thr->callstack_curr;
64754 thr->callstack_curr = act->parent;
64755 thr->callstack_top--;
64756
64757 /* Ideally we'd restore value stack reserve here to caller's value.
64758 * This doesn't work for current unwind call sites however, because
64759 * the current (unwound) value stack top may be above the reserve.
64760 * Thus value stack reserve is restored by the call sites.
64761 */
64762
64763 /* XXX: inline for performance builds? */
64764 duk_hthread_activation_free(thr, act);
64765
64766 /* We could clear the book-keeping variables like retval_byteoff for
64767 * the topmost activation, but don't do so now as it's not necessary.
64768 */
64769}
64770
64771DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) {
64772 duk__activation_unwind_nofree_norz(thr);
64773}
64774
64775/* Get duk_activation for given callstack level or NULL if level is invalid
64776 * or deeper than the call stack. Level -1 refers to current activation, -2
64777 * to its caller, etc. Starting from Duktape 2.2 finding the activation is
64778 * a linked list scan which gets more expensive the deeper the lookup is.
64779 */
64780DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) {
64781 duk_activation *act;
64782
64783 if (level >= 0) {
64784 return NULL;
64785 }
64786 act = thr->callstack_curr;
64787 for (;;) {
64788 if (act == NULL) {
64789 return act;
64790 }
64791 if (level == -1) {
64792 return act;
64793 }
64794 level++;
64795 act = act->parent;
64796 }
64797 /* never here */
64798}
64799
64800#if defined(DUK_USE_FINALIZER_TORTURE)
64801DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
64802 duk_size_t alloc_size;
64803 duk_tval *new_ptr;
64804 duk_ptrdiff_t alloc_end_off;
64805 duk_ptrdiff_t end_off;
64806 duk_ptrdiff_t bottom_off;
64807 duk_ptrdiff_t top_off;
64808
64809 if (thr->valstack == NULL) {
64810 DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL"));
64811 return;
64812 }
64813
64814 alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
64815 end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
64816 bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
64817 top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack);
64818 alloc_size = (duk_size_t) alloc_end_off;
64819 if (alloc_size == 0) {
64820 DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero"));
64821 return;
64822 }
64823
64824 /* Use DUK_ALLOC_RAW() to avoid side effects. */
64825 new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size);
64826 if (new_ptr != NULL) {
64827 duk_memcpy((void *) new_ptr, (const void *) thr->valstack, alloc_size);
64828 duk_memset((void *) thr->valstack, 0x55, alloc_size);
64829 DUK_FREE_CHECKED(thr, (void *) thr->valstack);
64830 thr->valstack = new_ptr;
64831 thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off);
64832 thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off);
64833 thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off);
64834 thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off);
64835 } else {
64836 DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore"));
64837 }
64838}
64839#endif /* DUK_USE_FINALIZER_TORTURE */
64840#line 1 "duk_js_arith.c"
64841/*
64842 * Shared helpers for arithmetic operations
64843 */
64844
64845/* #include duk_internal.h -> already included */
64846
64847/* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation
64848 * (implemented by remainder() in C99) but does seem to match ANSI C fmod().
64849 * Compare E5 Section 11.5.3 and "man fmod".
64850 */
64851DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
64852#if defined(DUK_USE_POW_WORKAROUNDS)
64853 /* Specific fixes to common fmod() implementation issues:
64854 * - test-bug-mingw-math-issues.js
64855 */
64856 if (DUK_ISINF(d2)) {
64857 if (DUK_ISINF(d1)) {
64858 return DUK_DOUBLE_NAN;
64859 } else {
64860 return d1;
64861 }
64862 } else if (duk_double_equals(d1, 0.0)) {
64863 /* d1 +/-0 is returned as is (preserving sign) except when
64864 * d2 is zero or NaN.
64865 */
64866 if (duk_double_equals(d2, 0.0) || DUK_ISNAN(d2)) {
64867 return DUK_DOUBLE_NAN;
64868 } else {
64869 return d1;
64870 }
64871 }
64872#else
64873 /* Some ISO C assumptions. */
64874 DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY), 1.0));
64875 DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY), -1.0));
64876 DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY), 1.0));
64877 DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY), -1.0));
64878 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
64879 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
64880 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
64881 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
64882 DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0);
64883 DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0);
64884 DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
64885 DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0);
64886 DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
64887 DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0);
64888 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0)));
64889 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0)));
64890 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0)));
64891 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0)));
64892 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN)));
64893 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN)));
64894#endif
64895
64896 return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
64897}
64898
64899/* Shared helper for Math.pow() and exponentiation operator. */
64900DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
64901 /* The ANSI C pow() semantics differ from ECMAScript.
64902 *
64903 * E.g. when x==1 and y is +/- infinite, the ECMAScript required
64904 * result is NaN, while at least Linux pow() returns 1.
64905 */
64906
64907 duk_small_int_t cx, cy, sx;
64908
64909 DUK_UNREF(cx);
64910 DUK_UNREF(sx);
64911 cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
64912
64913 if (cy == DUK_FP_NAN) {
64914 goto ret_nan;
64915 }
64916 if (duk_double_equals(DUK_FABS(x), 1.0) && cy == DUK_FP_INFINITE) {
64917 goto ret_nan;
64918 }
64919
64920#if defined(DUK_USE_POW_WORKAROUNDS)
64921 /* Specific fixes to common pow() implementation issues:
64922 * - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least)
64923 * - test-bug-mingw-math-issues.js
64924 */
64925 cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
64926 if (cx == DUK_FP_ZERO && y < 0.0) {
64927 sx = (duk_small_int_t) DUK_SIGNBIT(x);
64928 if (sx == 0) {
64929 /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
64930 * returns -Infinity instead when y is <0 and finite. The
64931 * if-clause also catches y == -Infinity (which works even
64932 * without the fix).
64933 */
64934 return DUK_DOUBLE_INFINITY;
64935 } else {
64936 /* Math.pow(-0,y) where y<0 should be:
64937 * - -Infinity if y<0 and an odd integer
64938 * - Infinity if y<0 but not an odd integer
64939 * NetBSD pow() returns -Infinity for all finite y<0. The
64940 * if-clause also catches y == -Infinity (which works even
64941 * without the fix).
64942 */
64943
64944 /* fmod() return value has same sign as input (negative) so
64945 * the result here will be in the range ]-2,0], -1 indicates
64946 * odd. If x is -Infinity, NaN is returned and the odd check
64947 * always concludes "not odd" which results in desired outcome.
64948 */
64949 double tmp = DUK_FMOD(y, 2);
64950 if (tmp == -1.0) {
64951 return -DUK_DOUBLE_INFINITY;
64952 } else {
64953 /* Not odd, or y == -Infinity */
64954 return DUK_DOUBLE_INFINITY;
64955 }
64956 }
64957 } else if (cx == DUK_FP_NAN) {
64958 if (duk_double_equals(y, 0.0)) {
64959 /* NaN ** +/- 0 should always be 1, but is NaN on
64960 * at least some Cygwin/MinGW versions.
64961 */
64962 return 1.0;
64963 }
64964 }
64965#else
64966 /* Some ISO C assumptions. */
64967 DUK_ASSERT(duk_double_equals(DUK_POW(DUK_DOUBLE_NAN, 0.0), 1.0));
64968 DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0);
64969 DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0);
64970 DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0);
64971#endif
64972
64973 return DUK_POW(x, y);
64974
64975 ret_nan:
64976 return DUK_DOUBLE_NAN;
64977}
64978#line 1 "duk_js_call.c"
64979/*
64980 * Call handling.
64981 *
64982 * duk_handle_call_unprotected():
64983 *
64984 * - Unprotected call to ECMAScript or Duktape/C function, from native
64985 * code or bytecode executor.
64986 *
64987 * - Also handles Ecma-to-Ecma calls which reuses a currently running
64988 * executor instance to avoid native recursion. Call setup is done
64989 * normally, but just before calling the bytecode executor a special
64990 * return code is used to indicate that a calling executor is reused.
64991 *
64992 * - Also handles tailcalls, i.e. reuse of current duk_activation.
64993 *
64994 * - Also handles setup for initial Duktape.Thread.resume().
64995 *
64996 * duk_handle_safe_call():
64997 *
64998 * - Protected C call within current activation.
64999 *
65000 * setjmp() and local variables have a nasty interaction, see execution.rst;
65001 * non-volatile locals modified after setjmp() call are not guaranteed to
65002 * keep their value and can cause compiler or compiler version specific
65003 * difficult to replicate issues.
65004 *
65005 * See 'execution.rst'.
65006 */
65007
65008/* #include duk_internal.h -> already included */
65009
65010/* XXX: heap->error_not_allowed for success path too? */
65011
65012/*
65013 * Limit check helpers.
65014 */
65015
65016/* Check native stack space if DUK_USE_NATIVE_STACK_CHECK() defined. */
65017DUK_INTERNAL void duk_native_stack_check(duk_hthread *thr) {
65018#if defined(DUK_USE_NATIVE_STACK_CHECK)
65019 if (DUK_USE_NATIVE_STACK_CHECK() != 0) {
65020 DUK_ERROR_RANGE(thr, DUK_STR_NATIVE_STACK_LIMIT);
65021 }
65022#else
65023 DUK_UNREF(thr);
65024#endif
65025}
65026
65027/* Allow headroom for calls during error augmentation (see GH-191).
65028 * We allow space for 10 additional recursions, with one extra
65029 * for, e.g. a print() call at the deepest level, and an extra
65030 * +1 for protected call wrapping.
65031 */
65032#define DUK__AUGMENT_CALL_RELAX_COUNT (10 + 2)
65033
65034/* Stack space required by call handling entry. */
65035#define DUK__CALL_HANDLING_REQUIRE_STACK 8
65036
65037DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) {
65038 /* When augmenting an error, the effective limit is a bit higher.
65039 * Check for it only if the fast path check fails.
65040 */
65041#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
65042 if (thr->heap->augmenting_error) {
65043 if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) {
65044 DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit"));
65045 return;
65046 }
65047 }
65048#endif
65049
65050 DUK_D(DUK_DPRINT("call prevented because C recursion limit reached"));
65051 DUK_ERROR_RANGE(thr, DUK_STR_NATIVE_STACK_LIMIT);
65052 DUK_WO_NORETURN(return;);
65053}
65054
65055DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) {
65056 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
65057 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
65058
65059 duk_native_stack_check(thr);
65060
65061 /* This check is forcibly inlined because it's very cheap and almost
65062 * always passes. The slow path is forcibly noinline.
65063 */
65064 if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) {
65065 return;
65066 }
65067
65068 duk__call_c_recursion_limit_check_slowpath(thr);
65069}
65070
65071DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) {
65072 /* When augmenting an error, the effective limit is a bit higher.
65073 * Check for it only if the fast path check fails.
65074 */
65075#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
65076 if (thr->heap->augmenting_error) {
65077 if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) {
65078 DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit"));
65079 return;
65080 }
65081 }
65082#endif
65083
65084 /* XXX: error message is a bit misleading: we reached a recursion
65085 * limit which is also essentially the same as a C callstack limit
65086 * (except perhaps with some relaxed threading assumptions).
65087 */
65088 DUK_D(DUK_DPRINT("call prevented because call stack limit reached"));
65089 DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
65090 DUK_WO_NORETURN(return;);
65091}
65092
65093DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) {
65094 /* This check is forcibly inlined because it's very cheap and almost
65095 * always passes. The slow path is forcibly noinline.
65096 */
65097 if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) {
65098 return;
65099 }
65100
65101 duk__call_callstack_limit_check_slowpath(thr);
65102}
65103
65104/*
65105 * Interrupt counter fixup (for development only).
65106 */
65107
65108#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
65109DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
65110 /* Currently the bytecode executor and executor interrupt
65111 * instruction counts are off because we don't execute the
65112 * interrupt handler when we're about to exit from the initial
65113 * user call into Duktape.
65114 *
65115 * If we were to execute the interrupt handler here, the counts
65116 * would match. You can enable this block manually to check
65117 * that this is the case.
65118 */
65119
65120 DUK_ASSERT(thr != NULL);
65121 DUK_ASSERT(thr->heap != NULL);
65122
65123#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
65124 if (entry_curr_thread == NULL) {
65125 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
65126 thr->heap->inst_count_interrupt += thr->interrupt_init;
65127 DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
65128 "user code, instruction counts: executor=%ld, interrupt=%ld",
65129 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
65130 DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
65131 }
65132#else
65133 DUK_UNREF(thr);
65134 DUK_UNREF(entry_curr_thread);
65135#endif
65136}
65137#endif
65138
65139/*
65140 * Arguments object creation.
65141 *
65142 * Creating arguments objects involves many small details, see E5 Section
65143 * 10.6 for the specific requirements. Much of the arguments object exotic
65144 * behavior is implemented in duk_hobject_props.c, and is enabled by the
65145 * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
65146 */
65147
65148DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
65149 duk_hobject *func,
65150 duk_hobject *varenv,
65151 duk_idx_t idx_args) {
65152 duk_hobject *arg; /* 'arguments' */
65153 duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
65154 duk_idx_t i_arg;
65155 duk_idx_t i_map;
65156 duk_idx_t i_mappednames;
65157 duk_idx_t i_formals;
65158 duk_idx_t i_argbase;
65159 duk_idx_t n_formals;
65160 duk_idx_t idx;
65161 duk_idx_t num_stack_args;
65162 duk_bool_t need_map;
65163
65164 DUK_ASSERT(thr != NULL);
65165 DUK_ASSERT(func != NULL);
65166 DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
65167 DUK_ASSERT(varenv != NULL);
65168
65169 /* [ ... func this arg1(@idx_args) ... argN envobj ]
65170 * [ arg1(@idx_args) ... argN envobj ] (for tailcalls)
65171 */
65172
65173 need_map = 0;
65174
65175 i_argbase = idx_args;
65176 num_stack_args = duk_get_top(thr) - i_argbase - 1;
65177 DUK_ASSERT(i_argbase >= 0);
65178 DUK_ASSERT(num_stack_args >= 0);
65179
65180 formals = (duk_hobject *) duk_hobject_get_formals(thr, (duk_hobject *) func);
65181 if (formals) {
65182 n_formals = (duk_idx_t) ((duk_harray *) formals)->length;
65183 duk_push_hobject(thr, formals);
65184 } else {
65185 /* This shouldn't happen without tampering of internal
65186 * properties: if a function accesses 'arguments', _Formals
65187 * is kept. Check for the case anyway in case internal
65188 * properties have been modified manually.
65189 */
65190 DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0"));
65191 n_formals = 0;
65192 duk_push_undefined(thr);
65193 }
65194 i_formals = duk_require_top_index(thr);
65195
65196 DUK_ASSERT(n_formals >= 0);
65197 DUK_ASSERT(formals != NULL || n_formals == 0);
65198
65199 DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
65200 (duk_heaphdr *) func, (duk_heaphdr *) formals,
65201 (long) n_formals));
65202
65203 /* [ ... formals ] */
65204
65205 /*
65206 * Create required objects:
65207 * - 'arguments' object: array-like, but not an array
65208 * - 'map' object: internal object, tied to 'arguments' (bare)
65209 * - 'mappedNames' object: temporary value used during construction (bare)
65210 */
65211
65212 arg = duk_push_object_helper(thr,
65213 DUK_HOBJECT_FLAG_EXTENSIBLE |
65214 DUK_HOBJECT_FLAG_FASTREFS |
65215 DUK_HOBJECT_FLAG_ARRAY_PART |
65216 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
65217 DUK_BIDX_OBJECT_PROTOTYPE);
65218 DUK_ASSERT(arg != NULL);
65219 (void) duk_push_object_helper(thr,
65220 DUK_HOBJECT_FLAG_EXTENSIBLE |
65221 DUK_HOBJECT_FLAG_FASTREFS |
65222 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
65223 -1); /* no prototype */
65224 (void) duk_push_object_helper(thr,
65225 DUK_HOBJECT_FLAG_EXTENSIBLE |
65226 DUK_HOBJECT_FLAG_FASTREFS |
65227 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
65228 -1); /* no prototype */
65229 i_arg = duk_get_top(thr) - 3;
65230 i_map = i_arg + 1;
65231 i_mappednames = i_arg + 2;
65232 DUK_ASSERT(!duk_is_bare_object(thr, -3)); /* arguments */
65233 DUK_ASSERT(duk_is_bare_object(thr, -2)); /* map */
65234 DUK_ASSERT(duk_is_bare_object(thr, -1)); /* mappedNames */
65235
65236 /* [ ... formals arguments map mappedNames ] */
65237
65238 DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
65239 "arguments at index %ld -> %!O "
65240 "map at index %ld -> %!O "
65241 "mappednames at index %ld -> %!O",
65242 (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
65243 (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
65244 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
65245
65246 /*
65247 * Init arguments properties, map, etc.
65248 */
65249
65250 duk_push_int(thr, num_stack_args);
65251 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
65252
65253 /*
65254 * Init argument related properties.
65255 */
65256
65257 /* step 11 */
65258 idx = num_stack_args - 1;
65259 while (idx >= 0) {
65260 DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
65261 (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
65262
65263 DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
65264 duk_dup(thr, i_argbase + idx);
65265 duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx);
65266 DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
65267
65268 /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
65269 if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
65270 DUK_ASSERT(formals != NULL);
65271
65272 DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
65273 (long) idx, (long) n_formals));
65274
65275 duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx);
65276 DUK_ASSERT(duk_is_string(thr, -1));
65277
65278 duk_dup_top(thr); /* [ ... name name ] */
65279
65280 if (!duk_has_prop(thr, i_mappednames)) {
65281 /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
65282 * differs from the reference model
65283 */
65284
65285 /* [ ... name ] */
65286
65287 need_map = 1;
65288
65289 DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
65290 (const char *) duk_get_string(thr, -1),
65291 (long) idx));
65292 duk_dup_top(thr); /* name */
65293 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx); /* index */
65294 duk_xdef_prop_wec(thr, i_mappednames); /* out of spec, must be configurable */
65295
65296 DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
65297 (long) idx,
65298 duk_get_string(thr, -1)));
65299 duk_dup_top(thr); /* name */
65300 duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
65301 } else {
65302 /* duk_has_prop() popped the second 'name' */
65303 }
65304
65305 /* [ ... name ] */
65306 duk_pop(thr); /* pop 'name' */
65307 }
65308
65309 idx--;
65310 }
65311
65312 DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
65313
65314 /* step 12 */
65315 if (need_map) {
65316 DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
65317
65318 /* should never happen for a strict callee */
65319 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
65320
65321 duk_dup(thr, i_map);
65322 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
65323
65324 /* The variable environment for magic variable bindings needs to be
65325 * given by the caller and recorded in the arguments object.
65326 *
65327 * See E5 Section 10.6, the creation of setters/getters.
65328 *
65329 * The variable environment also provides access to the callee, so
65330 * an explicit (internal) callee property is not needed.
65331 */
65332
65333 duk_push_hobject(thr, varenv);
65334 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
65335 }
65336
65337 /* steps 13-14 */
65338 if (DUK_HOBJECT_HAS_STRICT(func)) {
65339 /* Callee/caller are throwers and are not deletable etc. They
65340 * could be implemented as virtual properties, but currently
65341 * there is no support for virtual properties which are accessors
65342 * (only plain virtual properties). This would not be difficult
65343 * to change in duk_hobject_props, but we can make the throwers
65344 * normal, concrete properties just as easily.
65345 *
65346 * Note that the specification requires that the *same* thrower
65347 * built-in object is used here! See E5 Section 10.6 main
65348 * algoritm, step 14, and Section 13.2.3 which describes the
65349 * thrower. See test case test-arguments-throwers.js.
65350 */
65351
65352 DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
65353
65354 /* In ES2017 .caller is no longer set at all. */
65355 duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE);
65356 } else {
65357 DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
65358 duk_push_hobject(thr, func);
65359 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
65360 }
65361
65362 /* set exotic behavior only after we're done */
65363 if (need_map) {
65364 /* Exotic behaviors are only enabled for arguments objects
65365 * which have a parameter map (see E5 Section 10.6 main
65366 * algorithm, step 12).
65367 *
65368 * In particular, a non-strict arguments object with no
65369 * mapped formals does *NOT* get exotic behavior, even
65370 * for e.g. "caller" property. This seems counterintuitive
65371 * but seems to be the case.
65372 */
65373
65374 /* cannot be strict (never mapped variables) */
65375 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
65376
65377 DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
65378 DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
65379 } else {
65380 DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
65381 }
65382
65383 DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
65384 "arguments at index %ld -> %!O "
65385 "map at index %ld -> %!O "
65386 "mappednames at index %ld -> %!O",
65387 (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
65388 (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
65389 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
65390
65391 /* [ args(n) envobj formals arguments map mappednames ] */
65392
65393 duk_pop_2(thr);
65394 duk_remove_m2(thr);
65395
65396 /* [ args(n) envobj arguments ] */
65397}
65398
65399/* Helper for creating the arguments object and adding it to the env record
65400 * on top of the value stack.
65401 */
65402DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
65403 duk_hobject *func,
65404 duk_hobject *env,
65405 duk_idx_t idx_args) {
65406 DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
65407
65408 DUK_ASSERT(thr != NULL);
65409 DUK_ASSERT(func != NULL);
65410 DUK_ASSERT(env != NULL);
65411 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
65412
65413 /* [ ... arg1 ... argN envobj ] */
65414
65415 duk__create_arguments_object(thr,
65416 func,
65417 env,
65418 idx_args);
65419
65420 /* [ ... arg1 ... argN envobj argobj ] */
65421
65422 duk_xdef_prop_stridx_short(thr,
65423 -2,
65424 DUK_STRIDX_LC_ARGUMENTS,
65425 DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
65426 DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
65427 /* [ ... arg1 ... argN envobj ] */
65428}
65429
65430/*
65431 * Helpers for constructor call handling.
65432 *
65433 * There are two [[Construct]] operations in the specification:
65434 *
65435 * - E5 Section 13.2.2: for Function objects
65436 * - E5 Section 15.3.4.5.2: for "bound" Function objects
65437 *
65438 * The chain of bound functions is resolved in Section 15.3.4.5.2,
65439 * with arguments "piling up" until the [[Construct]] internal
65440 * method is called on the final, actual Function object. Note
65441 * that the "prototype" property is looked up *only* from the
65442 * final object, *before* calling the constructor.
65443 *
65444 * Since Duktape 2.2 bound functions are represented with the
65445 * duk_hboundfunc internal type, and bound function chains are
65446 * collapsed when a bound function is created. As a result, the
65447 * direct target of a duk_hboundfunc is always non-bound and the
65448 * this/argument lists have been resolved.
65449 *
65450 * When constructing new Array instances, an unnecessary object is
65451 * created and discarded now: the standard [[Construct]] creates an
65452 * object, and calls the Array constructor. The Array constructor
65453 * returns an Array instance, which is used as the result value for
65454 * the "new" operation; the object created before the Array constructor
65455 * call is discarded.
65456 *
65457 * This would be easy to fix, e.g. by knowing that the Array constructor
65458 * will always create a replacement object and skip creating the fallback
65459 * object in that case.
65460 */
65461
65462/* Update default instance prototype for constructor call. */
65463DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) {
65464 duk_hobject *proto;
65465 duk_hobject *fallback;
65466
65467 DUK_ASSERT(duk_is_constructable(thr, idx_func));
65468
65469 duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE);
65470 proto = duk_get_hobject(thr, -1);
65471 if (proto == NULL) {
65472 DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
65473 "-> leave standard Object prototype as fallback prototype"));
65474 } else {
65475 DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
65476 "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
65477 /* Original fallback (default instance) is untouched when
65478 * resolving bound functions etc.
65479 */
65480 fallback = duk_known_hobject(thr, idx_func + 1);
65481 DUK_ASSERT(fallback != NULL);
65482 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
65483 }
65484 duk_pop(thr);
65485}
65486
65487/* Postprocess: return value special handling, error augmentation. */
65488DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) {
65489 /* Use either fallback (default instance) or retval depending
65490 * on retval type. Needs to be called before unwind because
65491 * the default instance is read from the current (immutable)
65492 * 'this' binding.
65493 *
65494 * For Proxy 'construct' calls the return value must be an
65495 * Object (we accept object-like values like buffers and
65496 * lightfuncs too). If not, TypeError.
65497 */
65498 if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
65499 DUK_TYPE_MASK_BUFFER |
65500 DUK_TYPE_MASK_LIGHTFUNC)) {
65501 DUK_DDD(DUK_DDDPRINT("replacement value"));
65502 } else {
65503 if (DUK_UNLIKELY(proxy_invariant != 0U)) {
65504 /* Proxy 'construct' return value invariant violated. */
65505 DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
65506 DUK_WO_NORETURN(return;);
65507 }
65508 /* XXX: direct value stack access */
65509 duk_pop(thr);
65510 duk_push_this(thr);
65511 }
65512
65513#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
65514 /* Augment created errors upon creation, not when they are thrown or
65515 * rethrown. __FILE__ and __LINE__ are not desirable here; the call
65516 * stack reflects the caller which is correct. Skip topmost, unwound
65517 * activation when creating a traceback. If thr->ptr_curr_pc was !=
65518 * NULL we'd need to sync the current PC so that the traceback comes
65519 * out right; however it is always synced here so just assert for it.
65520 */
65521 DUK_ASSERT(thr->ptr_curr_pc == NULL);
65522 duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE |
65523 DUK_AUGMENT_FLAG_SKIP_ONE);
65524#endif
65525}
65526
65527/*
65528 * Helper for handling a bound function when a call is being made.
65529 *
65530 * Assumes that bound function chains have been "collapsed" so that either
65531 * the target is non-bound or there is one bound function that points to a
65532 * nonbound target.
65533 *
65534 * Prepends the bound arguments to the value stack (at idx_func + 2).
65535 * The 'this' binding is also updated if necessary (at idx_func + 1).
65536 * Note that for constructor calls the 'this' binding is never updated by
65537 * [[BoundThis]].
65538 */
65539
65540DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
65541 duk_idx_t idx_func,
65542 duk_bool_t is_constructor_call) {
65543 duk_tval *tv_func;
65544 duk_hobject *func;
65545 duk_idx_t len;
65546
65547 DUK_ASSERT(thr != NULL);
65548
65549 /* On entry, item at idx_func is a bound, non-lightweight function,
65550 * but we don't rely on that below.
65551 */
65552
65553 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65554
65555 tv_func = duk_require_tval(thr, idx_func);
65556 DUK_ASSERT(tv_func != NULL);
65557
65558 if (DUK_TVAL_IS_OBJECT(tv_func)) {
65559 func = DUK_TVAL_GET_OBJECT(tv_func);
65560
65561 /* XXX: separate helper function, out of fast path? */
65562 if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
65563 duk_hboundfunc *h_bound;
65564 duk_tval *tv_args;
65565 duk_tval *tv_gap;
65566
65567 h_bound = (duk_hboundfunc *) (void *) func;
65568 tv_args = h_bound->args;
65569 len = h_bound->nargs;
65570 DUK_ASSERT(len == 0 || tv_args != NULL);
65571
65572 DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T",
65573 (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func));
65574
65575 /* [ ... func this arg1 ... argN ] */
65576
65577 if (is_constructor_call) {
65578 /* See: tests/ecmascript/test-spec-bound-constructor.js */
65579 DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
65580 } else {
65581 /* XXX: duk_replace_tval */
65582 duk_push_tval(thr, &h_bound->this_binding);
65583 duk_replace(thr, idx_func + 1); /* idx_this = idx_func + 1 */
65584 }
65585
65586 /* [ ... func this arg1 ... argN ] */
65587
65588 duk_require_stack(thr, len);
65589
65590 tv_gap = duk_reserve_gap(thr, idx_func + 2, len);
65591 duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len);
65592
65593 /* [ ... func this <bound args> arg1 ... argN ] */
65594
65595 duk_push_tval(thr, &h_bound->target);
65596 duk_replace(thr, idx_func); /* replace in stack */
65597
65598 DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T",
65599 (long) idx_func, duk_get_tval(thr, idx_func)));
65600 }
65601 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
65602 /* Lightweight function: never bound, so terminate. */
65603 ;
65604 } else {
65605 /* Shouldn't happen, so ugly error is enough. */
65606 DUK_ERROR_INTERNAL(thr);
65607 DUK_WO_NORETURN(return;);
65608 }
65609
65610 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65611
65612 DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(thr, idx_func)));
65613
65614#if defined(DUK_USE_ASSERTIONS)
65615 tv_func = duk_require_tval(thr, idx_func);
65616 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
65617 if (DUK_TVAL_IS_OBJECT(tv_func)) {
65618 func = DUK_TVAL_GET_OBJECT(tv_func);
65619 DUK_ASSERT(func != NULL);
65620 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
65621 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) ||
65622 DUK_HOBJECT_HAS_NATFUNC(func) ||
65623 DUK_HOBJECT_IS_PROXY(func));
65624 }
65625#endif
65626}
65627
65628/*
65629 * Helper for inline handling of .call(), .apply(), and .construct().
65630 */
65631
65632DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hobject *func, duk_small_uint_t *call_flags, duk_bool_t first) {
65633#if defined(DUK_USE_ASSERTIONS)
65634 duk_c_function natfunc;
65635#endif
65636 duk_tval *tv_args;
65637
65638 DUK_ASSERT(func != NULL);
65639 DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0); /* Caller. */
65640
65641#if defined(DUK_USE_ASSERTIONS)
65642 natfunc = ((duk_hnatfunc *) func)->func;
65643 DUK_ASSERT(natfunc != NULL);
65644#endif
65645
65646 /* On every round of function resolution at least target function and
65647 * 'this' binding are set. We can assume that here, and must guarantee
65648 * it on exit. Value stack reserve is extended for bound function and
65649 * .apply() unpacking so we don't need to extend it here when we need a
65650 * few slots.
65651 */
65652 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65653
65654 /* Handle native 'eval' specially. A direct eval check is only made
65655 * for the first resolution attempt; e.g. a bound eval call is -not-
65656 * a direct eval call.
65657 */
65658 if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) {
65659 /* For now no special handling except for direct eval
65660 * detection.
65661 */
65662 DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval);
65663 if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) {
65664 *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL;
65665 }
65666 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65667 return 1; /* stop resolving */
65668 }
65669
65670 /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL
65671 * flag; their magic value is used for switch-case.
65672 *
65673 * NOTE: duk_unpack_array_like() reserves value stack space
65674 * for the result values (unlike most other value stack calls).
65675 */
65676 switch (((duk_hnatfunc *) func)->magic) {
65677 case 0: { /* 0=Function.prototype.call() */
65678 /* Value stack:
65679 * idx_func + 0: Function.prototype.call() [removed]
65680 * idx_func + 1: this binding for .call (target function)
65681 * idx_func + 2: 1st argument to .call, desired 'this' binding
65682 * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target
65683 * ...
65684 *
65685 * Remove idx_func + 0 to get:
65686 * idx_func + 0: target function
65687 * idx_func + 1: this binding
65688 * idx_func + 2: call arguments
65689 * ...
65690 */
65691 DUK_ASSERT(natfunc == duk_bi_function_prototype_call);
65692 duk_remove_unsafe(thr, idx_func);
65693 tv_args = thr->valstack_bottom + idx_func + 2;
65694 if (thr->valstack_top < tv_args) {
65695 DUK_ASSERT(tv_args <= thr->valstack_end);
65696 thr->valstack_top = tv_args; /* at least target function and 'this' binding present */
65697 }
65698 break;
65699 }
65700 case 1: { /* 1=Function.prototype.apply() */
65701 /* Value stack:
65702 * idx_func + 0: Function.prototype.apply() [removed]
65703 * idx_func + 1: this binding for .apply (target function)
65704 * idx_func + 2: 1st argument to .apply, desired 'this' binding
65705 * idx_func + 3: 2nd argument to .apply, argArray
65706 * [anything after this MUST be ignored]
65707 *
65708 * Remove idx_func + 0 and unpack the argArray to get:
65709 * idx_func + 0: target function
65710 * idx_func + 1: this binding
65711 * idx_func + 2: call arguments
65712 * ...
65713 */
65714 DUK_ASSERT(natfunc == duk_bi_function_prototype_apply);
65715 duk_remove_unsafe(thr, idx_func);
65716 goto apply_shared;
65717 }
65718#if defined(DUK_USE_REFLECT_BUILTIN)
65719 case 2: { /* 2=Reflect.apply() */
65720 /* Value stack:
65721 * idx_func + 0: Reflect.apply() [removed]
65722 * idx_func + 1: this binding for .apply (ignored, usually Reflect) [removed]
65723 * idx_func + 2: 1st argument to .apply, target function
65724 * idx_func + 3: 2nd argument to .apply, desired 'this' binding
65725 * idx_func + 4: 3rd argument to .apply, argArray
65726 * [anything after this MUST be ignored]
65727 *
65728 * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get:
65729 * idx_func + 0: target function
65730 * idx_func + 1: this binding
65731 * idx_func + 2: call arguments
65732 * ...
65733 */
65734 DUK_ASSERT(natfunc == duk_bi_reflect_apply);
65735 duk_remove_n_unsafe(thr, idx_func, 2);
65736 goto apply_shared;
65737 }
65738 case 3: { /* 3=Reflect.construct() */
65739 /* Value stack:
65740 * idx_func + 0: Reflect.construct() [removed]
65741 * idx_func + 1: this binding for .construct (ignored, usually Reflect) [removed]
65742 * idx_func + 2: 1st argument to .construct, target function
65743 * idx_func + 3: 2nd argument to .construct, argArray
65744 * idx_func + 4: 3rd argument to .construct, newTarget
65745 * [anything after this MUST be ignored]
65746 *
65747 * Remove idx_func + 0 and idx_func + 1, unpack the argArray,
65748 * and insert default instance (prototype not yet updated), to get:
65749 * idx_func + 0: target function
65750 * idx_func + 1: this binding (default instance)
65751 * idx_func + 2: constructor call arguments
65752 * ...
65753 *
65754 * Call flags must be updated to reflect the fact that we're
65755 * now dealing with a constructor call, and e.g. the 'this'
65756 * binding cannot be overwritten if the target is bound.
65757 *
65758 * newTarget is checked but not yet passed onwards.
65759 */
65760
65761 duk_idx_t top;
65762
65763 DUK_ASSERT(natfunc == duk_bi_reflect_construct);
65764 *call_flags |= DUK_CALL_FLAG_CONSTRUCT;
65765 duk_remove_n_unsafe(thr, idx_func, 2);
65766 top = duk_get_top(thr);
65767 if (!duk_is_constructable(thr, idx_func)) {
65768 /* Target constructability must be checked before
65769 * unpacking argArray (which may cause side effects).
65770 * Just return; caller will throw the error.
65771 */
65772 duk_set_top_unsafe(thr, idx_func + 2); /* satisfy asserts */
65773 break;
65774 }
65775 duk_push_object(thr);
65776 duk_insert(thr, idx_func + 1); /* default instance */
65777
65778 /* [ ... func default_instance argArray newTarget? ] */
65779
65780 top = duk_get_top(thr);
65781 if (top < idx_func + 3) {
65782 /* argArray is a mandatory argument for Reflect.construct(). */
65783 DUK_ERROR_TYPE_INVALID_ARGS(thr);
65784 DUK_WO_NORETURN(return 0;);
65785 }
65786 if (top > idx_func + 3) {
65787 if (!duk_strict_equals(thr, idx_func, idx_func + 3)) {
65788 /* XXX: [[Construct]] newTarget currently unsupported */
65789 DUK_ERROR_UNSUPPORTED(thr);
65790 DUK_WO_NORETURN(return 0;);
65791 }
65792 duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
65793 }
65794 DUK_ASSERT(duk_get_top(thr) == idx_func + 3);
65795 DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
65796 (void) duk_unpack_array_like(thr, idx_func + 2); /* XXX: should also remove target to be symmetric with duk_pack()? */
65797 duk_remove(thr, idx_func + 2);
65798 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65799 break;
65800 }
65801#endif /* DUK_USE_REFLECT_BUILTIN */
65802 default: {
65803 DUK_ASSERT(0);
65804 DUK_UNREACHABLE();
65805 }
65806 }
65807
65808 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65809 return 0; /* keep resolving */
65810
65811 apply_shared:
65812 tv_args = thr->valstack_bottom + idx_func + 2;
65813 if (thr->valstack_top <= tv_args) {
65814 DUK_ASSERT(tv_args <= thr->valstack_end);
65815 thr->valstack_top = tv_args; /* at least target func and 'this' binding present */
65816 /* No need to check for argArray. */
65817 } else {
65818 DUK_ASSERT(duk_get_top(thr) >= idx_func + 3); /* idx_func + 2 covered above */
65819 if (thr->valstack_top > tv_args + 1) {
65820 duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
65821 }
65822 DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
65823 if (!duk_is_callable(thr, idx_func)) {
65824 /* Avoid unpack side effects if the target isn't callable.
65825 * Calling code will throw the actual error.
65826 */
65827 } else {
65828 (void) duk_unpack_array_like(thr, idx_func + 2);
65829 duk_remove(thr, idx_func + 2);
65830 }
65831 }
65832 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
65833 return 0; /* keep resolving */
65834}
65835
65836/*
65837 * Helper for Proxy handling.
65838 */
65839
65840#if defined(DUK_USE_ES6_PROXY)
65841DUK_LOCAL void duk__handle_proxy_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hproxy *h_proxy, duk_small_uint_t *call_flags) {
65842 duk_bool_t rc;
65843
65844 /* Value stack:
65845 * idx_func + 0: Proxy object
65846 * idx_func + 1: this binding for call
65847 * idx_func + 2: 1st argument for call
65848 * idx_func + 3: 2nd argument for call
65849 * ...
65850 *
65851 * If Proxy doesn't have a trap for the call ('apply' or 'construct'),
65852 * replace Proxy object with target object.
65853 *
65854 * If we're dealing with a normal call and the Proxy has an 'apply'
65855 * trap, manipulate value stack to:
65856 *
65857 * idx_func + 0: trap
65858 * idx_func + 1: Proxy's handler
65859 * idx_func + 2: Proxy's target
65860 * idx_func + 3: this binding for call (from idx_func + 1)
65861 * idx_func + 4: call arguments packed to an array
65862 *
65863 * If we're dealing with a constructor call and the Proxy has a
65864 * 'construct' trap, manipulate value stack to:
65865 *
65866 * idx_func + 0: trap
65867 * idx_func + 1: Proxy's handler
65868 * idx_func + 2: Proxy's target
65869 * idx_func + 3: call arguments packed to an array
65870 * idx_func + 4: newTarget == Proxy object here
65871 *
65872 * As we don't yet have proper newTarget support, the newTarget at
65873 * idx_func + 3 is just the original constructor being called, i.e.
65874 * the Proxy object (not the target). Note that the default instance
65875 * (original 'this' binding) is dropped and ignored.
65876 */
65877
65878 duk_push_hobject(thr, h_proxy->handler);
65879 rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY);
65880 if (rc == 0) {
65881 /* Not found, continue to target. If this is a construct
65882 * call, update default instance prototype using the Proxy,
65883 * not the target.
65884 */
65885 if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
65886 if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
65887 *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
65888 duk__update_default_instance_proto(thr, idx_func);
65889 }
65890 }
65891 duk_pop_2(thr);
65892 duk_push_hobject(thr, h_proxy->target);
65893 duk_replace(thr, idx_func);
65894 return;
65895 }
65896
65897 /* Here we must be careful not to replace idx_func while
65898 * h_proxy is still needed, otherwise h_proxy may become
65899 * dangling. This could be improved e.g. using a
65900 * duk_pack_slice() with a freeform slice.
65901 */
65902
65903 /* Here:
65904 * idx_func + 0: Proxy object
65905 * idx_func + 1: this binding for call
65906 * idx_func + 2: 1st argument for call
65907 * idx_func + 3: 2nd argument for call
65908 * ...
65909 * idx_func + N: handler
65910 * idx_func + N + 1: trap
65911 */
65912
65913 duk_insert(thr, idx_func + 1);
65914 duk_insert(thr, idx_func + 2);
65915 duk_push_hobject(thr, h_proxy->target);
65916 duk_insert(thr, idx_func + 3);
65917 duk_pack(thr, duk_get_top(thr) - (idx_func + 5));
65918 DUK_ASSERT(!duk_is_bare_object(thr, -1));
65919
65920 /* Here:
65921 * idx_func + 0: Proxy object
65922 * idx_func + 1: trap
65923 * idx_func + 2: Proxy's handler
65924 * idx_func + 3: Proxy's target
65925 * idx_func + 4: this binding for call
65926 * idx_func + 5: arguments array
65927 */
65928 DUK_ASSERT(duk_get_top(thr) == idx_func + 6);
65929
65930 if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
65931 *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY; /* Enable 'construct' trap return invariant check. */
65932 *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT); /* Resume as non-constructor call to the trap. */
65933
65934 /* 'apply' args: target, thisArg, argArray
65935 * 'construct' args: target, argArray, newTarget
65936 */
65937 duk_remove(thr, idx_func + 4);
65938 duk_push_hobject(thr, (duk_hobject *) h_proxy);
65939 }
65940
65941 /* Finalize value stack layout by removing Proxy reference. */
65942 duk_remove(thr, idx_func);
65943 h_proxy = NULL; /* invalidated */
65944 DUK_ASSERT(duk_get_top(thr) == idx_func + 5);
65945}
65946#endif /* DUK_USE_ES6_PROXY */
65947
65948/*
65949 * Helper for setting up var_env and lex_env of an activation,
65950 * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
65951 */
65952
65953DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
65954 duk_hobject *func,
65955 duk_activation *act) {
65956 duk_hcompfunc *f;
65957 duk_hobject *h_lex;
65958 duk_hobject *h_var;
65959
65960 DUK_ASSERT(thr != NULL);
65961 DUK_ASSERT(func != NULL);
65962 DUK_ASSERT(act != NULL);
65963 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
65964 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
65965 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
65966 DUK_UNREF(thr);
65967
65968 f = (duk_hcompfunc *) func;
65969 h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
65970 h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f);
65971 DUK_ASSERT(h_lex != NULL); /* Always true for closures (not for templates) */
65972 DUK_ASSERT(h_var != NULL);
65973 act->lex_env = h_lex;
65974 act->var_env = h_var;
65975 DUK_HOBJECT_INCREF(thr, h_lex);
65976 DUK_HOBJECT_INCREF(thr, h_var);
65977}
65978
65979/*
65980 * Helper for updating callee 'caller' property.
65981 */
65982
65983#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
65984DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
65985 duk_tval *tv_caller;
65986 duk_hobject *h_tmp;
65987 duk_activation *act_callee;
65988 duk_activation *act_caller;
65989
65990 DUK_ASSERT(thr != NULL);
65991 DUK_ASSERT(func != NULL);
65992 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound chain resolved */
65993 DUK_ASSERT(thr->callstack_top >= 1);
65994
65995 if (DUK_HOBJECT_HAS_STRICT(func)) {
65996 /* Strict functions don't get their 'caller' updated. */
65997 return;
65998 }
65999
66000 DUK_ASSERT(thr->callstack_top > 0);
66001 act_callee = thr->callstack_curr;
66002 DUK_ASSERT(act_callee != NULL);
66003 act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL);
66004
66005 /* XXX: check .caller writability? */
66006
66007 /* Backup 'caller' property and update its value. */
66008 tv_caller = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, func, DUK_STRIDX_CALLER);
66009 if (tv_caller) {
66010 /* If caller is global/eval code, 'caller' should be set to
66011 * 'null'.
66012 *
66013 * XXX: there is no exotic flag to infer this correctly now.
66014 * The NEWENV flag is used now which works as intended for
66015 * everything (global code, non-strict eval code, and functions)
66016 * except strict eval code. Bound functions are never an issue
66017 * because 'func' has been resolved to a non-bound function.
66018 */
66019
66020 if (act_caller != NULL) {
66021 /* act_caller->func may be NULL in some finalization cases,
66022 * just treat like we don't know the caller.
66023 */
66024 if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
66025 /* Setting to NULL causes 'caller' to be set to
66026 * 'null' as desired.
66027 */
66028 act_caller = NULL;
66029 }
66030 }
66031
66032 if (DUK_TVAL_IS_OBJECT(tv_caller)) {
66033 h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
66034 DUK_ASSERT(h_tmp != NULL);
66035 act_callee->prev_caller = h_tmp;
66036
66037 /* Previous value doesn't need refcount changes because its ownership
66038 * is transferred to prev_caller.
66039 */
66040
66041 if (act_caller != NULL) {
66042 DUK_ASSERT(act_caller->func != NULL);
66043 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
66044 DUK_TVAL_INCREF(thr, tv_caller);
66045 } else {
66046 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
66047 }
66048 } else {
66049 /* 'caller' must only take on 'null' or function value */
66050 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
66051 DUK_ASSERT(act_callee->prev_caller == NULL);
66052 if (act_caller != NULL && act_caller->func) {
66053 /* Tolerate act_caller->func == NULL which happens in
66054 * some finalization cases; treat like unknown caller.
66055 */
66056 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
66057 DUK_TVAL_INCREF(thr, tv_caller);
66058 } else {
66059 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
66060 }
66061 }
66062 }
66063}
66064#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
66065
66066/*
66067 * Shared helpers for resolving the final, non-bound target function of the
66068 * call and the effective 'this' binding. Resolves bound functions and
66069 * applies .call(), .apply(), and .construct() inline.
66070 *
66071 * Proxy traps are also handled inline so that if the target is a Proxy with
66072 * a 'call' or 'construct' trap, the trap handler is called with a modified
66073 * argument list.
66074 *
66075 * Once the bound function / .call() / .apply() / .construct() sequence has
66076 * been resolved, the value at idx_func + 1 may need coercion described in
66077 * E5 Section 10.4.3.
66078 *
66079 * A call that begins as a non-constructor call may be converted into a
66080 * constructor call during the resolution process if Reflect.construct()
66081 * is invoked. This is handled by updating the caller's call_flags.
66082 *
66083 * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
66084 * that the caller has provided the correct 'this' binding explicitly
66085 * when calling, i.e.:
66086 *
66087 * - global code: this=global object
66088 * - direct eval: this=copy from eval() caller's this binding
66089 * - other eval: this=global object
66090 *
66091 * The 'this' coercion may cause a recursive function call with arbitrary
66092 * side effects, because ToObject() may be called.
66093 */
66094
66095DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) {
66096 duk_tval *tv_this;
66097 duk_hobject *obj_global;
66098
66099 tv_this = thr->valstack_bottom + idx_this;
66100 switch (DUK_TVAL_GET_TAG(tv_this)) {
66101 case DUK_TAG_OBJECT:
66102 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
66103 break;
66104 case DUK_TAG_UNDEFINED:
66105 case DUK_TAG_NULL:
66106 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
66107 obj_global = thr->builtins[DUK_BIDX_GLOBAL];
66108 /* XXX: avoid this check somehow */
66109 if (DUK_LIKELY(obj_global != NULL)) {
66110 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
66111 DUK_TVAL_SET_OBJECT(tv_this, obj_global);
66112 DUK_HOBJECT_INCREF(thr, obj_global);
66113 } else {
66114 /* This may only happen if built-ins are being "torn down".
66115 * This behavior is out of specification scope.
66116 */
66117 DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
66118 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
66119 DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
66120 }
66121 break;
66122 default:
66123 /* Plain buffers and lightfuncs are object coerced. Lightfuncs
66124 * very rarely come here however, because the call target would
66125 * need to be a non-strict non-lightfunc (lightfuncs are considered
66126 * strict) with an explicit lightfunc 'this' binding.
66127 */
66128 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
66129 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
66130 duk_to_object(thr, idx_this); /* may have side effects */
66131 break;
66132 }
66133}
66134
66135DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__resolve_target_fastpath_check(duk_hthread *thr, duk_idx_t idx_func, duk_hobject **out_func, duk_small_uint_t call_flags) {
66136#if defined(DUK_USE_PREFER_SIZE)
66137 DUK_UNREF(thr);
66138 DUK_UNREF(idx_func);
66139 DUK_UNREF(out_func);
66140 DUK_UNREF(call_flags);
66141#else /* DUK_USE_PREFER_SIZE */
66142 duk_tval *tv_func;
66143 duk_hobject *func;
66144
66145 if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) {
66146 return 0;
66147 }
66148
66149 tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
66150 DUK_ASSERT(tv_func != NULL);
66151
66152 if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) {
66153 func = DUK_TVAL_GET_OBJECT(tv_func);
66154 if (DUK_HOBJECT_IS_CALLABLE(func) &&
66155 !DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
66156 !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) {
66157 *out_func = func;
66158
66159 if (DUK_HOBJECT_HAS_STRICT(func)) {
66160 /* Strict function: no 'this' coercion. */
66161 return 1;
66162 }
66163
66164 duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
66165 return 1;
66166 }
66167 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
66168 *out_func = NULL;
66169
66170 /* Lightfuncs are considered strict, so 'this' binding is
66171 * used as is. They're never bound, always constructable,
66172 * and never special functions.
66173 */
66174 return 1;
66175 }
66176#endif /* DUK_USE_PREFER_SIZE */
66177 return 0; /* let slow path deal with it */
66178}
66179
66180DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr,
66181 duk_idx_t idx_func,
66182 duk_small_uint_t *call_flags) {
66183 duk_tval *tv_func;
66184 duk_hobject *func;
66185 duk_bool_t first;
66186
66187 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
66188
66189 for (first = 1;; first = 0) {
66190 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
66191
66192 tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
66193 DUK_ASSERT(tv_func != NULL);
66194
66195 DUK_DD(DUK_DDPRINT("target func: %!iT", tv_func));
66196
66197 if (DUK_TVAL_IS_OBJECT(tv_func)) {
66198 func = DUK_TVAL_GET_OBJECT(tv_func);
66199
66200 if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
66201 if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) {
66202 goto not_constructable;
66203 }
66204 } else {
66205 if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) {
66206 goto not_callable;
66207 }
66208 }
66209
66210 if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
66211 !DUK_HOBJECT_HAS_SPECIAL_CALL(func) &&
66212 !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) {
66213 /* Common case, so test for using a single bitfield test.
66214 * Break out to handle this coercion etc.
66215 */
66216 break;
66217 }
66218
66219 /* XXX: could set specialcall for boundfuncs too, simplify check above */
66220
66221 if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
66222 DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func));
66223 DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func));
66224
66225 /* Callable/constructable flags are the same
66226 * for the bound function and its target, so
66227 * we don't need to check them here, we can
66228 * check them from the target only.
66229 */
66230 duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT);
66231
66232 DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) ||
66233 DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func)));
66234 } else {
66235 DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func));
66236
66237#if defined(DUK_USE_ES6_PROXY)
66238 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) {
66239 /* If no trap, resume processing from Proxy trap.
66240 * If trap exists, helper converts call into a trap
66241 * call; this may change a constructor call into a
66242 * normal (non-constructor) trap call. We must
66243 * continue processing even when a trap is found as
66244 * the trap may be bound.
66245 */
66246 duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags);
66247 }
66248 else
66249#endif
66250 {
66251 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
66252 DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func));
66253 DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func));
66254 /* Constructable check already done above. */
66255
66256 if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) {
66257 /* Encountered native eval call, normal call
66258 * context. Break out, handle this coercion etc.
66259 */
66260 break;
66261 }
66262 }
66263 }
66264 /* Retry loop. */
66265 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
66266 /* Lightfuncs are:
66267 * - Always strict, so no 'this' coercion.
66268 * - Always callable.
66269 * - Always constructable.
66270 * - Never specialfuncs.
66271 */
66272 func = NULL;
66273 goto finished;
66274 } else {
66275 goto not_callable;
66276 }
66277 }
66278
66279 DUK_ASSERT(func != NULL);
66280
66281 if (!DUK_HOBJECT_HAS_STRICT(func)) {
66282 /* Non-strict target needs 'this' coercion.
66283 * This has potential side effects invalidating
66284 * 'tv_func'.
66285 */
66286 duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
66287 }
66288 if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
66289 if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
66290 *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
66291 duk__update_default_instance_proto(thr, idx_func);
66292 }
66293 }
66294
66295 finished:
66296
66297#if defined(DUK_USE_ASSERTIONS)
66298 {
66299 duk_tval *tv_tmp;
66300
66301 tv_tmp = duk_get_tval(thr, idx_func);
66302 DUK_ASSERT(tv_tmp != NULL);
66303
66304 DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) ||
66305 DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
66306 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
66307 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
66308 DUK_HOBJECT_IS_NATFUNC(func)));
66309 DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) ||
66310 (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0));
66311 }
66312#endif
66313
66314 return func;
66315
66316 not_callable:
66317 DUK_ASSERT(tv_func != NULL);
66318
66319#if defined(DUK_USE_VERBOSE_ERRORS)
66320 /* GETPROPC delayed error handling: when target is not callable,
66321 * GETPROPC replaces idx_func+0 with a non-callable wrapper object
66322 * with a hidden Symbol to signify it's to be handled here. If
66323 * found, unwrap the original Error and throw it as is here. The
66324 * hidden Symbol is only checked as an own property, not inherited
66325 * (which would be dangerous).
66326 */
66327 if (DUK_TVAL_IS_OBJECT(tv_func)) {
66328 duk_tval *tv_wrap = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_STRIDX_INT_TARGET);
66329 if (tv_wrap != NULL) {
66330 DUK_DD(DUK_DDPRINT("delayed error from GETPROPC: %!T", tv_wrap));
66331 duk_push_tval(thr, tv_wrap);
66332 (void) duk_throw(thr);
66333 DUK_WO_NORETURN(return NULL;);
66334 }
66335 }
66336#endif
66337
66338#if defined(DUK_USE_VERBOSE_ERRORS)
66339#if defined(DUK_USE_PARANOID_ERRORS)
66340 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_get_type_name(thr, idx_func));
66341#else
66342 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(thr, tv_func));
66343#endif
66344#else
66345 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
66346#endif
66347 DUK_WO_NORETURN(return NULL;);
66348
66349 not_constructable:
66350 /* For now GETPROPC delayed error not needed for constructor calls. */
66351#if defined(DUK_USE_VERBOSE_ERRORS)
66352#if defined(DUK_USE_PARANOID_ERRORS)
66353 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(thr, idx_func));
66354#else
66355 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_tval_readable(thr, tv_func));
66356#endif
66357#else
66358 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
66359#endif
66360 DUK_WO_NORETURN(return NULL;);
66361}
66362
66363/*
66364 * Manipulate value stack so that exactly 'num_stack_rets' return
66365 * values are at 'idx_retbase' in every case, assuming there are
66366 * 'rc' return values on top of stack.
66367 *
66368 * This is a bit tricky, because the called C function operates in
66369 * the same activation record and may have e.g. popped the stack
66370 * empty (below idx_retbase).
66371 */
66372
66373DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
66374 duk_idx_t idx_rcbase;
66375
66376 DUK_ASSERT(thr != NULL);
66377 DUK_ASSERT(idx_retbase >= 0);
66378 DUK_ASSERT(num_stack_rets >= 0);
66379 DUK_ASSERT(num_actual_rets >= 0);
66380
66381 idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */
66382 if (DUK_UNLIKELY(idx_rcbase < 0)) {
66383 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
66384 DUK_WO_NORETURN(return;);
66385 }
66386
66387 DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
66388 "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
66389 (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr),
66390 (long) idx_retbase, (long) idx_rcbase));
66391
66392 DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
66393
66394 /* Space for num_stack_rets was reserved before the safe call.
66395 * Because value stack reserve cannot shrink except in call returns,
66396 * the reserve is still in place. Adjust valstack, carefully
66397 * ensuring we don't overstep the reserve.
66398 */
66399
66400 /* Match idx_rcbase with idx_retbase so that the return values
66401 * start at the correct index.
66402 */
66403 if (idx_rcbase > idx_retbase) {
66404 duk_idx_t count = idx_rcbase - idx_retbase;
66405
66406 DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
66407 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
66408
66409 /* Remove values between irc_rcbase (start of intended return
66410 * values) and idx_retbase to lower return values to idx_retbase.
66411 */
66412 DUK_ASSERT(count > 0);
66413 duk_remove_n(thr, idx_retbase, count); /* may be NORZ */
66414 } else {
66415 duk_idx_t count = idx_retbase - idx_rcbase;
66416
66417 DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
66418 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
66419
66420 /* Insert 'undefined' at idx_rcbase (start of intended return
66421 * values) to lift return values to idx_retbase.
66422 */
66423 DUK_ASSERT(count >= 0);
66424 DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count); /* reserve cannot shrink */
66425 duk_insert_undefined_n(thr, idx_rcbase, count);
66426 }
66427
66428 /* Chop extra retvals away / extend with undefined. */
66429 duk_set_top_unsafe(thr, idx_retbase + num_stack_rets);
66430}
66431
66432/*
66433 * Activation setup for tailcalls and non-tailcalls.
66434 */
66435
66436#if defined(DUK_USE_TAILCALL)
66437DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr,
66438 duk_small_uint_t call_flags,
66439 duk_idx_t idx_func,
66440 duk_hobject *func,
66441 duk_size_t entry_valstack_bottom_byteoff,
66442 duk_size_t entry_valstack_end_byteoff,
66443 duk_idx_t *out_nargs,
66444 duk_idx_t *out_nregs,
66445 duk_size_t *out_vs_min_bytes,
66446 duk_activation **out_act) {
66447 duk_activation *act;
66448 duk_tval *tv1, *tv2;
66449 duk_idx_t idx_args;
66450 duk_small_uint_t flags1, flags2;
66451#if defined(DUK_USE_DEBUGGER_SUPPORT)
66452 duk_activation *prev_pause_act;
66453#endif
66454
66455 DUK_UNREF(entry_valstack_end_byteoff);
66456
66457 /* Tailcall cannot be flagged to resume calls, and a
66458 * previous frame must exist.
66459 */
66460 DUK_ASSERT(thr->callstack_top >= 1);
66461
66462 act = thr->callstack_curr;
66463 DUK_ASSERT(act != NULL);
66464 *out_act = act;
66465
66466 if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
66467 DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function"));
66468 return 0;
66469 }
66470 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
66471 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD"));
66472 return 0;
66473 }
66474 /* Tailcall is only allowed if current and candidate
66475 * function have identical return value handling. There
66476 * are three possible return value handling cases:
66477 * 1. Normal function call, no special return value handling.
66478 * 2. Constructor call, return value replacement object check.
66479 * 3. Proxy 'construct' trap call, return value invariant check.
66480 */
66481 flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0)
66482#if defined(DUK_USE_ES6_PROXY)
66483 | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0)
66484#endif
66485 ;
66486 flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0)
66487#if defined(DUK_USE_ES6_PROXY)
66488 | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0);
66489#endif
66490 ;
66491 if (flags1 != flags2) {
66492 DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling"));
66493 return 0;
66494 }
66495 DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) ||
66496 (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT)));
66497 DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) ||
66498 (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)));
66499 if (DUK_HOBJECT_HAS_NOTAIL(func)) {
66500 /* See: test-bug-tailcall-preventyield-assert.c. */
66501 DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag"));
66502 return 0;
66503 }
66504
66505 /*
66506 * Tailcall handling
66507 *
66508 * Although the callstack entry is reused, we need to explicitly unwind
66509 * the current activation (or simulate an unwind). In particular, the
66510 * current activation must be closed, otherwise something like
66511 * test-bug-reduce-judofyr.js results. Also catchers need to be unwound
66512 * because there may be non-error-catching label entries in valid tail calls.
66513 *
66514 * Special attention is needed for debugger and pause behavior when
66515 * reusing an activation.
66516 * - Disable StepOut processing for the activation unwind because
66517 * we reuse the activation, see:
66518 * https://github.com/svaarala/duktape/issues/1684.
66519 * - Disable line change pause flag permanently if act == dbg_pause_act
66520 * (if set) because it would no longer be relevant, see:
66521 * https://github.com/svaarala/duktape/issues/1726,
66522 * https://github.com/svaarala/duktape/issues/1786.
66523 * - Check for function entry (e.g. StepInto) pause flag here, because
66524 * the executor pause check won't trigger due to shared activation, see:
66525 * https://github.com/svaarala/duktape/issues/1726.
66526 */
66527
66528 DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
66529 (long) (thr->callstack_top - 1)));
66530
66531 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
66532 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
66533 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
66534 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
66535 DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA);
66536
66537 /* Unwind the topmost callstack entry before reusing it. This
66538 * also unwinds the catchers related to the topmost entry.
66539 */
66540 DUK_ASSERT(thr->callstack_top > 0);
66541 DUK_ASSERT(thr->callstack_curr != NULL);
66542#if defined(DUK_USE_DEBUGGER_SUPPORT)
66543 if (act == thr->heap->dbg_pause_act) {
66544 thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
66545 }
66546
66547 prev_pause_act = thr->heap->dbg_pause_act;
66548 thr->heap->dbg_pause_act = NULL;
66549 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) {
66550 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)"));
66551 duk_debug_set_paused(thr->heap);
66552 }
66553#endif
66554 duk_hthread_activation_unwind_reuse_norz(thr);
66555#if defined(DUK_USE_DEBUGGER_SUPPORT)
66556 thr->heap->dbg_pause_act = prev_pause_act;
66557#endif
66558 DUK_ASSERT(act == thr->callstack_curr);
66559
66560 /* XXX: We could restore the caller's value stack reserve
66561 * here, as if we did an actual unwind-and-call. Without
66562 * the restoration, value stack reserve may remain higher
66563 * than would otherwise be possible until we return to a
66564 * non-tailcall.
66565 */
66566
66567 /* Then reuse the unwound activation. */
66568 act->cat = NULL;
66569 act->var_env = NULL;
66570 act->lex_env = NULL;
66571 DUK_ASSERT(func != NULL);
66572 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
66573 act->func = func; /* don't want an intermediate exposed state with func == NULL */
66574#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
66575 act->prev_caller = NULL;
66576#endif
66577 /* don't want an intermediate exposed state with invalid pc */
66578 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
66579#if defined(DUK_USE_DEBUGGER_SUPPORT)
66580 act->prev_line = 0;
66581#endif
66582 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
66583 DUK_HOBJECT_INCREF(thr, func);
66584
66585 act->flags = DUK_ACT_FLAG_TAILCALLED;
66586 if (DUK_HOBJECT_HAS_STRICT(func)) {
66587 act->flags |= DUK_ACT_FLAG_STRICT;
66588 }
66589 if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
66590 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
66591 }
66592#if defined(DUK_USE_ES6_PROXY)
66593 if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
66594 act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
66595 }
66596#endif
66597
66598 DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
66599 DUK_ASSERT(act->var_env == NULL);
66600 DUK_ASSERT(act->lex_env == NULL);
66601 act->bottom_byteoff = entry_valstack_bottom_byteoff; /* tail call -> reuse current "frame" */
66602#if 0
66603 /* Topmost activation retval_byteoff is considered garbage, no need to init. */
66604 act->retval_byteoff = 0;
66605#endif
66606 /* Filled in when final reserve is known, dummy value doesn't matter
66607 * even in error unwind because reserve_byteoff is only used when
66608 * returning to -this- activation.
66609 */
66610 act->reserve_byteoff = 0;
66611
66612 /*
66613 * Manipulate valstack so that args are on the current bottom and the
66614 * previous caller's 'this' binding (which is the value preceding the
66615 * current bottom) is replaced with the new 'this' binding:
66616 *
66617 * [ ... this_old | (crud) func this_new arg1 ... argN ]
66618 * --> [ ... this_new | arg1 ... argN ]
66619 *
66620 * For tail calling to work properly, the valstack bottom must not grow
66621 * here; otherwise crud would accumulate on the valstack.
66622 */
66623
66624 tv1 = thr->valstack_bottom - 1;
66625 tv2 = thr->valstack_bottom + idx_func + 1;
66626 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
66627 DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
66628 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
66629
66630 idx_args = idx_func + 2;
66631 duk_remove_n(thr, 0, idx_args); /* may be NORZ */
66632
66633 idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
66634 idx_args = 0;
66635
66636 *out_nargs = ((duk_hcompfunc *) func)->nargs;
66637 *out_nregs = ((duk_hcompfunc *) func)->nregs;
66638 DUK_ASSERT(*out_nregs >= 0);
66639 DUK_ASSERT(*out_nregs >= *out_nargs);
66640 *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
66641
66642
66643#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
66644#if defined(DUK_USE_TAILCALL)
66645#error incorrect options: tail calls enabled with function caller property
66646#endif
66647 /* XXX: This doesn't actually work properly for tail calls, so
66648 * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
66649 * is in use.
66650 */
66651 duk__update_func_caller_prop(thr, func);
66652#endif
66653
66654 /* [ ... this_new | arg1 ... argN ] */
66655
66656 return 1;
66657}
66658#endif /* DUK_USE_TAILCALL */
66659
66660DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr,
66661 duk_small_uint_t call_flags,
66662 duk_idx_t idx_func,
66663 duk_hobject *func,
66664 duk_size_t entry_valstack_bottom_byteoff,
66665 duk_size_t entry_valstack_end_byteoff,
66666 duk_idx_t *out_nargs,
66667 duk_idx_t *out_nregs,
66668 duk_size_t *out_vs_min_bytes,
66669 duk_activation **out_act) {
66670 duk_activation *act;
66671 duk_activation *new_act;
66672
66673 DUK_UNREF(entry_valstack_end_byteoff);
66674
66675 DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
66676 (long) (thr->callstack_top)));
66677
66678 duk__call_callstack_limit_check(thr);
66679 new_act = duk_hthread_activation_alloc(thr);
66680 DUK_ASSERT(new_act != NULL);
66681
66682 act = thr->callstack_curr;
66683 if (act != NULL) {
66684 /*
66685 * Update return value stack index of current activation (if any).
66686 *
66687 * Although it might seem this is not necessary (bytecode executor
66688 * does this for ECMAScript-to-ECMAScript calls; other calls are
66689 * handled here), this turns out to be necessary for handling yield
66690 * and resume. For them, an ECMAScript-to-native call happens, and
66691 * the ECMAScript call's retval_byteoff must be set for things to work.
66692 */
66693
66694 act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval);
66695 }
66696
66697 new_act->parent = act;
66698 thr->callstack_curr = new_act;
66699 thr->callstack_top++;
66700 act = new_act;
66701 *out_act = act;
66702
66703 DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
66704 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
66705
66706 act->cat = NULL;
66707
66708 act->flags = 0;
66709 if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
66710 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
66711 }
66712#if defined(DUK_USE_ES6_PROXY)
66713 if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
66714 act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
66715 }
66716#endif
66717 if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
66718 act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
66719 }
66720
66721 /* start of arguments: idx_func + 2. */
66722 act->func = func; /* NULL for lightfunc */
66723 if (DUK_LIKELY(func != NULL)) {
66724 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
66725 if (DUK_HOBJECT_HAS_STRICT(func)) {
66726 act->flags |= DUK_ACT_FLAG_STRICT;
66727 }
66728 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
66729 *out_nargs = ((duk_hcompfunc *) func)->nargs;
66730 *out_nregs = ((duk_hcompfunc *) func)->nregs;
66731 DUK_ASSERT(*out_nregs >= 0);
66732 DUK_ASSERT(*out_nregs >= *out_nargs);
66733 *out_vs_min_bytes = entry_valstack_bottom_byteoff +
66734 sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
66735 } else {
66736 /* True because of call target lookup checks. */
66737 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
66738
66739 *out_nargs = ((duk_hnatfunc *) func)->nargs;
66740 *out_nregs = *out_nargs;
66741 if (*out_nargs >= 0) {
66742 *out_vs_min_bytes = entry_valstack_bottom_byteoff +
66743 sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
66744 } else {
66745 /* Vararg function. */
66746 duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
66747 *out_vs_min_bytes = valstack_top_byteoff +
66748 sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
66749 }
66750 }
66751 } else {
66752 duk_small_uint_t lf_flags;
66753 duk_tval *tv_func;
66754
66755 act->flags |= DUK_ACT_FLAG_STRICT;
66756
66757 tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
66758 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
66759 DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
66760
66761 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
66762 *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
66763 if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) {
66764 *out_vs_min_bytes = entry_valstack_bottom_byteoff +
66765 sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
66766 } else {
66767 duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
66768 *out_vs_min_bytes = valstack_top_byteoff +
66769 sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
66770 *out_nargs = -1; /* vararg */
66771 }
66772 *out_nregs = *out_nargs;
66773 }
66774
66775 act->var_env = NULL;
66776 act->lex_env = NULL;
66777#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
66778 act->prev_caller = NULL;
66779#endif
66780 act->curr_pc = NULL;
66781#if defined(DUK_USE_DEBUGGER_SUPPORT)
66782 act->prev_line = 0;
66783#endif
66784 act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U);
66785#if 0
66786 act->retval_byteoff = 0; /* topmost activation retval_byteoff is considered garbage, no need to init */
66787#endif
66788 /* Filled in when final reserve is known, dummy value doesn't matter
66789 * even in error unwind because reserve_byteoff is only used when
66790 * returning to -this- activation.
66791 */
66792 act->reserve_byteoff = 0; /* filled in by caller */
66793
66794 /* XXX: Is this INCREF necessary? 'func' is always a borrowed
66795 * reference reachable through the value stack? If changed, stack
66796 * unwind code also needs to be fixed to match.
66797 */
66798 DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
66799
66800#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
66801 if (func) {
66802 duk__update_func_caller_prop(thr, func);
66803 }
66804#endif
66805}
66806
66807/*
66808 * Environment setup.
66809 */
66810
66811DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) {
66812 duk_hobject *env;
66813
66814 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function has already been resolved */
66815
66816 if (DUK_LIKELY(func != NULL)) {
66817 if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
66818 DUK_STATS_INC(thr->heap, stats_envrec_newenv);
66819 if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
66820 /* Use a new environment but there's no 'arguments' object;
66821 * delayed environment initialization. This is the most
66822 * common case.
66823 */
66824 DUK_ASSERT(act->lex_env == NULL);
66825 DUK_ASSERT(act->var_env == NULL);
66826 } else {
66827 /* Use a new environment and there's an 'arguments' object.
66828 * We need to initialize it right now.
66829 */
66830
66831 /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */
66832 env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
66833 DUK_ASSERT(env != NULL);
66834
66835 /* [ ... func this arg1 ... argN envobj ] */
66836
66837 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
66838 duk__handle_createargs_for_call(thr, func, env, idx_args);
66839
66840 /* [ ... func this arg1 ... argN envobj ] */
66841
66842 act->lex_env = env;
66843 act->var_env = env;
66844 DUK_HOBJECT_INCREF(thr, env);
66845 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
66846 duk_pop(thr);
66847 }
66848 } else {
66849 /* Use existing env (e.g. for non-strict eval); cannot have
66850 * an own 'arguments' object (but can refer to an existing one).
66851 */
66852
66853 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
66854
66855 DUK_STATS_INC(thr->heap, stats_envrec_oldenv);
66856 duk__handle_oldenv_for_call(thr, func, act);
66857
66858 DUK_ASSERT(act->lex_env != NULL);
66859 DUK_ASSERT(act->var_env != NULL);
66860 }
66861 } else {
66862 /* Lightfuncs are always native functions and have "newenv". */
66863 DUK_ASSERT(act->lex_env == NULL);
66864 DUK_ASSERT(act->var_env == NULL);
66865 DUK_STATS_INC(thr->heap, stats_envrec_newenv);
66866 }
66867}
66868
66869/*
66870 * Misc shared helpers.
66871 */
66872
66873/* Check thread state, update current thread. */
66874DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) {
66875 DUK_ASSERT(thr != NULL);
66876
66877 if (DUK_LIKELY(thr == thr->heap->curr_thread)) {
66878 if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) {
66879 /* Should actually never happen, but check anyway. */
66880 goto thread_state_error;
66881 }
66882 } else {
66883 DUK_ASSERT(thr->heap->curr_thread == NULL ||
66884 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
66885 if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) {
66886 goto thread_state_error;
66887 }
66888 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
66889 thr->state = DUK_HTHREAD_STATE_RUNNING;
66890
66891 /* Multiple threads may be simultaneously in the RUNNING
66892 * state, but not in the same "resume chain".
66893 */
66894 }
66895 DUK_ASSERT(thr->heap->curr_thread == thr);
66896 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
66897 return;
66898
66899 thread_state_error:
66900 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state);
66901 DUK_WO_NORETURN(return;);
66902}
66903
66904/*
66905 * Main unprotected call handler, handles:
66906 *
66907 * - All combinations of native/ECMAScript caller and native/ECMAScript
66908 * target.
66909 *
66910 * - Optimized ECMAScript-to-ECMAScript call where call handling only
66911 * sets up a new duk_activation but reuses an existing bytecode executor
66912 * (the caller) without native recursion.
66913 *
66914 * - Tailcalls, where an activation is reused without increasing call
66915 * stack (duk_activation) depth.
66916 *
66917 * - Setup for an initial Duktape.Thread.resume().
66918 *
66919 * The call handler doesn't provide any protection guarantees, protected calls
66920 * must be implemented e.g. by wrapping the call in a duk_safe_call().
66921 * Call setup may fail at any stage, even when the new activation is in
66922 * place; the only guarantee is that the state is consistent for unwinding.
66923 */
66924
66925DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
66926 duk_idx_t idx_func,
66927 duk_small_uint_t call_flags) {
66928#if defined(DUK_USE_ASSERTIONS)
66929 duk_activation *entry_act;
66930 duk_size_t entry_callstack_top;
66931#endif
66932 duk_size_t entry_valstack_bottom_byteoff;
66933 duk_size_t entry_valstack_end_byteoff;
66934 duk_int_t entry_call_recursion_depth;
66935 duk_hthread *entry_curr_thread;
66936 duk_uint_fast8_t entry_thread_state;
66937 duk_instr_t **entry_ptr_curr_pc;
66938 duk_idx_t idx_args;
66939 duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
66940 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
66941 duk_size_t vs_min_bytes; /* minimum value stack size (bytes) for handling call */
66942 duk_hobject *func; /* 'func' on stack (borrowed reference) */
66943 duk_activation *act;
66944 duk_ret_t rc;
66945 duk_small_uint_t use_tailcall;
66946
66947 DUK_ASSERT(thr != NULL);
66948 DUK_ASSERT(thr->heap != NULL);
66949 /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or
66950 * any other thread (e.g. when heap thread is used to run finalizers).
66951 */
66952 DUK_CTX_ASSERT_VALID(thr);
66953 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
66954 DUK_ASSERT(idx_func >= 0);
66955
66956 DUK_STATS_INC(thr->heap, stats_call_all);
66957
66958 /* If a tail call:
66959 * - an ECMAScript activation must be on top of the callstack
66960 * - there cannot be any catch stack entries that would catch
66961 * a return
66962 */
66963#if defined(DUK_USE_ASSERTIONS)
66964 if (call_flags & DUK_CALL_FLAG_TAILCALL) {
66965 duk_activation *tmp_act;
66966 duk_catcher *tmp_cat;
66967
66968 DUK_ASSERT(thr->callstack_top >= 1);
66969 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
66970 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
66971
66972 /* No entry in the catch stack which would actually catch a
66973 * throw can refer to the callstack entry being reused.
66974 * There *can* be catch stack entries referring to the current
66975 * callstack entry as long as they don't catch (e.g. label sites).
66976 */
66977
66978 tmp_act = thr->callstack_curr;
66979 for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) {
66980 DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */
66981 }
66982 }
66983#endif /* DUK_USE_ASSERTIONS */
66984
66985 /*
66986 * Store entry state.
66987 */
66988
66989#if defined(DUK_USE_ASSERTIONS)
66990 entry_act = thr->callstack_curr;
66991 entry_callstack_top = thr->callstack_top;
66992#endif
66993 entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
66994 entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
66995 entry_call_recursion_depth = thr->heap->call_recursion_depth;
66996 entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
66997 entry_thread_state = thr->state;
66998 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
66999
67000 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
67001 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
67002 * activation when side effects occur.
67003 */
67004 duk_hthread_sync_and_null_currpc(thr);
67005 DUK_ASSERT(thr->ptr_curr_pc == NULL);
67006
67007 DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, "
67008 "call_flags=0x%08lx (constructor=%ld), "
67009 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
67010 "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, "
67011 "entry_call_recursion_depth=%ld, "
67012 "entry_curr_thread=%p, entry_thread_state=%ld",
67013 (void *) thr,
67014 (long) idx_func,
67015 (unsigned long) call_flags,
67016 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0),
67017 (long) duk_get_top(thr),
67018 (long) idx_func,
67019 (long) (idx_func + 2),
67020 (long) thr->heap->call_recursion_depth,
67021 (long) thr->heap->call_recursion_limit,
67022 (long) entry_valstack_bottom_byteoff,
67023 (long) entry_valstack_end_byteoff,
67024 (long) entry_call_recursion_depth,
67025 (void *) entry_curr_thread,
67026 (long) entry_thread_state));
67027
67028 /*
67029 * Thread state check and book-keeping.
67030 */
67031
67032 duk__call_thread_state_update(thr);
67033
67034 /*
67035 * Increase call recursion depth as early as possible so that if we
67036 * enter a recursive call for any reason there's a backstop to native
67037 * recursion. This can happen e.g. for almost any property read
67038 * because it may cause a getter call or a Proxy trap (GC and finalizers
67039 * are not an issue because they are not recursive). If we end up
67040 * doing an Ecma-to-Ecma call, revert the increase. (See GH-2032.)
67041 *
67042 * For similar reasons, ensure there is a known value stack spare
67043 * even before we actually prepare the value stack for the target
67044 * function. If this isn't done, early recursion may consume the
67045 * value stack space.
67046 *
67047 * XXX: Should bump yield preventcount early, for the same reason.
67048 */
67049
67050 duk__call_c_recursion_limit_check(thr);
67051 thr->heap->call_recursion_depth++;
67052 duk_require_stack(thr, DUK__CALL_HANDLING_REQUIRE_STACK);
67053
67054 /*
67055 * Resolve final target function; handle bound functions and special
67056 * functions like .call() and .apply(). Also figure out the effective
67057 * 'this' binding, which replaces the current value at idx_func + 1.
67058 */
67059
67060 if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) {
67061 DUK_DDD(DUK_DDDPRINT("fast path target resolve"));
67062 } else {
67063 DUK_DDD(DUK_DDDPRINT("slow path target resolve"));
67064 func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags);
67065 }
67066 DUK_ASSERT(duk_get_top(thr) - idx_func >= 2); /* at least func and this present */
67067
67068 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
67069 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
67070 DUK_HOBJECT_IS_NATFUNC(func)));
67071
67072 /* [ ... func this arg1 ... argN ] */
67073
67074 /*
67075 * Setup a preliminary activation and figure out nargs/nregs and
67076 * value stack minimum size.
67077 *
67078 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
67079 * calls work normally.
67080 *
67081 * Because 'act' is not zeroed, all fields must be filled in.
67082 */
67083
67084 /* Should not be necessary, but initialize to silence warnings. */
67085 act = NULL;
67086 nargs = 0;
67087 nregs = 0;
67088 vs_min_bytes = 0;
67089
67090#if defined(DUK_USE_TAILCALL)
67091 use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL);
67092 if (use_tailcall) {
67093 use_tailcall = duk__call_setup_act_attempt_tailcall(thr,
67094 call_flags,
67095 idx_func,
67096 func,
67097 entry_valstack_bottom_byteoff,
67098 entry_valstack_end_byteoff,
67099 &nargs,
67100 &nregs,
67101 &vs_min_bytes,
67102 &act);
67103 }
67104#else
67105 DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0); /* compiler ensures this */
67106 use_tailcall = 0;
67107#endif
67108
67109 if (use_tailcall) {
67110 idx_args = 0;
67111 DUK_STATS_INC(thr->heap, stats_call_tailcall);
67112 } else {
67113 duk__call_setup_act_not_tailcall(thr,
67114 call_flags,
67115 idx_func,
67116 func,
67117 entry_valstack_bottom_byteoff,
67118 entry_valstack_end_byteoff,
67119 &nargs,
67120 &nregs,
67121 &vs_min_bytes,
67122 &act);
67123 idx_args = idx_func + 2;
67124 }
67125 /* After this point idx_func is no longer valid for tailcalls. */
67126
67127 DUK_ASSERT(act != NULL);
67128
67129 /* [ ... func this arg1 ... argN ] */
67130
67131 /*
67132 * Environment record creation and 'arguments' object creation.
67133 * Named function expression name binding is handled by the
67134 * compiler; the compiled function's parent env will contain
67135 * the (immutable) binding already.
67136 *
67137 * This handling is now identical for C and ECMAScript functions.
67138 * C functions always have the 'NEWENV' flag set, so their
67139 * environment record initialization is delayed (which is good).
67140 *
67141 * Delayed creation (on demand) is handled in duk_js_var.c.
67142 */
67143
67144 duk__call_env_setup(thr, func, act, idx_args);
67145
67146 /* [ ... func this arg1 ... argN ] */
67147
67148 /*
67149 * Setup value stack: clamp to 'nargs', fill up to 'nregs',
67150 * ensure value stack size matches target requirements, and
67151 * switch value stack bottom. Valstack top is kept.
67152 *
67153 * Value stack can only grow here.
67154 */
67155
67156 duk_valstack_grow_check_throw(thr, vs_min_bytes);
67157 act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
67158
67159 if (use_tailcall) {
67160 DUK_ASSERT(nregs >= 0);
67161 DUK_ASSERT(nregs >= nargs);
67162 duk_set_top_and_wipe(thr, nregs, nargs);
67163 } else {
67164 if (nregs >= 0) {
67165 DUK_ASSERT(nregs >= nargs);
67166 duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs);
67167 } else {
67168 ;
67169 }
67170 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
67171 }
67172 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
67173 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
67174 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
67175
67176 /*
67177 * Make the actual call. For Ecma-to-Ecma calls detect that
67178 * setup is complete, then return with a status code that allows
67179 * the caller to reuse the running executor.
67180 */
67181
67182 if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
67183 /*
67184 * ECMAScript call.
67185 */
67186
67187 DUK_ASSERT(func != NULL);
67188 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
67189 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
67190
67191 if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) {
67192 DUK_DD(DUK_DDPRINT("avoid native call, use existing executor"));
67193 DUK_STATS_INC(thr->heap, stats_call_ecmatoecma);
67194 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
67195 DUK_REFZERO_CHECK_FAST(thr);
67196 DUK_ASSERT(thr->ptr_curr_pc == NULL);
67197 thr->heap->call_recursion_depth--; /* No recursion increase for this case. */
67198 return 1; /* 1=reuse executor */
67199 }
67200 DUK_ASSERT(use_tailcall == 0);
67201
67202 /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
67203 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
67204 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
67205 thr->callstack_preventcount++;
67206
67207 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
67208
67209 /*
67210 * Bytecode executor call.
67211 *
67212 * Execute bytecode, handling any recursive function calls and
67213 * thread resumptions. Returns when execution would return from
67214 * the entry level activation. When the executor returns, a
67215 * single return value is left on the stack top.
67216 *
67217 * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
67218 * other types are handled internally by the executor.
67219 */
67220
67221 /* thr->ptr_curr_pc is set by bytecode executor early on entry */
67222 DUK_ASSERT(thr->ptr_curr_pc == NULL);
67223 DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
67224 duk_js_execute_bytecode(thr);
67225 DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
67226 } else {
67227 /*
67228 * Native call.
67229 */
67230
67231 DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL);
67232 DUK_ASSERT(use_tailcall == 0);
67233
67234 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
67235
67236 /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
67237 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
67238 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
67239 thr->callstack_preventcount++;
67240
67241 /* For native calls must be NULL so we don't sync back */
67242 DUK_ASSERT(thr->ptr_curr_pc == NULL);
67243
67244 /* XXX: native funcptr could come out of call setup. */
67245 if (func) {
67246 rc = ((duk_hnatfunc *) func)->func(thr);
67247 } else {
67248 duk_tval *tv_func;
67249 duk_c_function funcptr;
67250
67251 tv_func = &act->tv_func;
67252 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
67253 funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
67254 rc = funcptr(thr);
67255 }
67256
67257 /* Automatic error throwing, retval check. */
67258
67259 if (rc == 0) {
67260 DUK_ASSERT(thr->valstack < thr->valstack_end);
67261 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
67262 thr->valstack_top++;
67263 } else if (rc == 1) {
67264 ;
67265 } else if (rc < 0) {
67266 duk_error_throw_from_negative_rc(thr, rc);
67267 DUK_WO_NORETURN(return 0;);
67268 } else {
67269 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
67270 DUK_WO_NORETURN(return 0;);
67271 }
67272 }
67273 DUK_ASSERT(thr->ptr_curr_pc == NULL);
67274 DUK_ASSERT(use_tailcall == 0);
67275
67276 /*
67277 * Constructor call post processing.
67278 */
67279
67280#if defined(DUK_USE_ES6_PROXY)
67281 if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) {
67282 duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY);
67283 }
67284#else
67285 if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
67286 duk_call_construct_postprocess(thr, 0);
67287 }
67288#endif
67289
67290 /*
67291 * Unwind, restore valstack bottom and other book-keeping.
67292 */
67293
67294 DUK_ASSERT(thr->callstack_curr != NULL);
67295 DUK_ASSERT(thr->callstack_curr->parent == entry_act);
67296 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
67297 duk_hthread_activation_unwind_norz(thr);
67298 DUK_ASSERT(thr->callstack_curr == entry_act);
67299 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
67300
67301 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
67302 /* keep current valstack_top */
67303 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
67304 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
67305 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
67306 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
67307
67308 /* Return value handling. */
67309
67310 /* [ ... func this (crud) retval ] */
67311
67312 {
67313 duk_tval *tv_ret;
67314 duk_tval *tv_funret;
67315
67316 tv_ret = thr->valstack_bottom + idx_func;
67317 tv_funret = thr->valstack_top - 1;
67318#if defined(DUK_USE_FASTINT)
67319 /* Explicit check for fastint downgrade. */
67320 DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
67321#endif
67322 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
67323 }
67324
67325 duk_set_top_unsafe(thr, idx_func + 1);
67326
67327 /* [ ... retval ] */
67328
67329 /* Restore caller's value stack reserve (cannot fail). */
67330 DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top);
67331 DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end);
67332 thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff);
67333
67334 /* XXX: Trial value stack shrink would be OK here, but we'd need
67335 * to prevent side effects of the potential realloc.
67336 */
67337
67338 /* Restore entry thread executor curr_pc stack frame pointer. */
67339 thr->ptr_curr_pc = entry_ptr_curr_pc;
67340
67341 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
67342 thr->state = (duk_uint8_t) entry_thread_state;
67343
67344 /* Disabled assert: triggered with some torture tests. */
67345#if 0
67346 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
67347 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
67348 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
67349#endif
67350
67351 thr->heap->call_recursion_depth = entry_call_recursion_depth;
67352
67353 /* If the debugger is active we need to force an interrupt so that
67354 * debugger breakpoints are rechecked. This is important for function
67355 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
67356 * GH-303. Only needed for success path, error path always causes a
67357 * breakpoint recheck in the executor. It would be enough to set this
67358 * only when returning to an ECMAScript activation, but setting the flag
67359 * on every return should have no ill effect.
67360 */
67361#if defined(DUK_USE_DEBUGGER_SUPPORT)
67362 if (duk_debug_is_attached(thr->heap)) {
67363 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
67364 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
67365 thr->interrupt_init -= thr->interrupt_counter;
67366 thr->interrupt_counter = 0;
67367 thr->heap->dbg_force_restart = 1;
67368 }
67369#endif
67370
67371#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
67372 duk__interrupt_fixup(thr, entry_curr_thread);
67373#endif
67374
67375 /* Restored by success path. */
67376 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
67377 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
67378 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
67379
67380 DUK_REFZERO_CHECK_FAST(thr);
67381
67382 return 0; /* 0=call handled inline */
67383}
67384
67385DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr,
67386 duk_idx_t nargs,
67387 duk_small_uint_t call_flags) {
67388 duk_idx_t idx_func;
67389 DUK_ASSERT(duk_get_top(thr) >= nargs + 2);
67390 idx_func = duk_get_top(thr) - (nargs + 2);
67391 DUK_ASSERT(idx_func >= 0);
67392 return duk_handle_call_unprotected(thr, idx_func, call_flags);
67393}
67394
67395DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr,
67396 duk_idx_t idx_func,
67397 duk_small_uint_t call_flags) {
67398 DUK_ASSERT(duk_is_valid_index(thr, idx_func));
67399 DUK_ASSERT(idx_func >= 0);
67400 return duk__handle_call_raw(thr, idx_func, call_flags);
67401}
67402
67403/*
67404 * duk_handle_safe_call(): make a "C protected call" within the
67405 * current activation.
67406 *
67407 * The allowed thread states for making a call are the same as for
67408 * duk_handle_call_protected().
67409 *
67410 * Even though this call is protected, errors are thrown for insane arguments
67411 * and may result in a fatal error unless there's another protected call which
67412 * catches such errors.
67413 *
67414 * The error handling path should be error free, even for out-of-memory
67415 * errors, to ensure safe sandboxing. (As of Duktape 2.2.0 this is not
67416 * yet the case for environment closing which may run out of memory, see
67417 * XXX notes below.)
67418 */
67419
67420DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
67421 duk_safe_call_function func,
67422 void *udata,
67423#if defined(DUK_USE_ASSERTIONS)
67424 duk_size_t entry_valstack_bottom_byteoff,
67425 duk_size_t entry_callstack_top,
67426#endif
67427 duk_hthread *entry_curr_thread,
67428 duk_uint_fast8_t entry_thread_state,
67429 duk_idx_t idx_retbase,
67430 duk_idx_t num_stack_rets) {
67431 duk_ret_t rc;
67432
67433 DUK_ASSERT(thr != NULL);
67434 DUK_CTX_ASSERT_VALID(thr);
67435
67436 /*
67437 * Thread state check and book-keeping.
67438 */
67439
67440 duk__call_thread_state_update(thr);
67441
67442 /*
67443 * Recursion limit check.
67444 */
67445
67446 duk__call_c_recursion_limit_check(thr);
67447 thr->heap->call_recursion_depth++;
67448
67449 /*
67450 * Make the C call.
67451 */
67452
67453 rc = func(thr, udata);
67454
67455 DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
67456
67457 /*
67458 * Valstack manipulation for results.
67459 */
67460
67461 /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
67462 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
67463 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
67464 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
67465 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
67466 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
67467
67468 if (DUK_UNLIKELY(rc < 0)) {
67469 duk_error_throw_from_negative_rc(thr, rc);
67470 DUK_WO_NORETURN(return;);
67471 }
67472 DUK_ASSERT(rc >= 0);
67473
67474 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); /* throws for insane rc */
67475
67476 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
67477 thr->state = (duk_uint8_t) entry_thread_state;
67478}
67479
67480DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
67481 duk_activation *entry_act,
67482#if defined(DUK_USE_ASSERTIONS)
67483 duk_size_t entry_callstack_top,
67484#endif
67485 duk_hthread *entry_curr_thread,
67486 duk_uint_fast8_t entry_thread_state,
67487 duk_idx_t idx_retbase,
67488 duk_idx_t num_stack_rets,
67489 duk_size_t entry_valstack_bottom_byteoff,
67490 duk_jmpbuf *old_jmpbuf_ptr) {
67491 DUK_ASSERT(thr != NULL);
67492 DUK_CTX_ASSERT_VALID(thr);
67493
67494 /*
67495 * Error during call. The error value is at heap->lj.value1.
67496 *
67497 * The very first thing we do is restore the previous setjmp catcher.
67498 * This means that any error in error handling will propagate outwards
67499 * instead of causing a setjmp() re-entry above.
67500 */
67501
67502 DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
67503
67504 /* Other longjmp types are handled by executor before propagating
67505 * the error here.
67506 */
67507 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
67508 DUK_ASSERT_LJSTATE_SET(thr->heap);
67509
67510 /* Either pointer may be NULL (at entry), so don't assert. */
67511 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
67512
67513 /* XXX: callstack unwind may now throw an error when closing
67514 * scopes; this is a sandboxing issue, described in:
67515 * https://github.com/svaarala/duktape/issues/476
67516 */
67517 /* XXX: "unwind to" primitive? */
67518
67519 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
67520 while (thr->callstack_curr != entry_act) {
67521 DUK_ASSERT(thr->callstack_curr != NULL);
67522 duk_hthread_activation_unwind_norz(thr);
67523 }
67524 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
67525
67526 /* Switch active thread before any side effects to avoid a
67527 * dangling curr_thread pointer.
67528 */
67529 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
67530 thr->state = (duk_uint8_t) entry_thread_state;
67531
67532 DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
67533 DUK_ASSERT(thr->state == entry_thread_state);
67534
67535 /* Restore valstack bottom. */
67536 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
67537
67538 /* [ ... | (crud) ] */
67539
67540 /* XXX: ensure space in valstack (now relies on internal reserve)? */
67541 duk_push_tval(thr, &thr->heap->lj.value1);
67542
67543 /* [ ... | (crud) errobj ] */
67544
67545 DUK_ASSERT(duk_get_top(thr) >= 1); /* at least errobj must be on stack */
67546
67547 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
67548
67549 /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
67550
67551 /* Reset longjmp state. */
67552 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
67553 thr->heap->lj.iserror = 0;
67554 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1);
67555 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2);
67556
67557 /* Error handling complete, remove side effect protections. Caller
67558 * will process pending finalizers.
67559 */
67560#if defined(DUK_USE_ASSERTIONS)
67561 DUK_ASSERT(thr->heap->error_not_allowed == 1);
67562 thr->heap->error_not_allowed = 0;
67563#endif
67564 DUK_ASSERT(thr->heap->pf_prevent_count > 0);
67565 thr->heap->pf_prevent_count--;
67566 DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count));
67567
67568 /* thr->ptr_curr_pc is restored by
67569 * duk__handle_safe_call_shared_unwind() which is also used for
67570 * success path.
67571 */
67572}
67573
67574DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr,
67575 duk_idx_t idx_retbase,
67576 duk_idx_t num_stack_rets,
67577#if defined(DUK_USE_ASSERTIONS)
67578 duk_size_t entry_callstack_top,
67579#endif
67580 duk_int_t entry_call_recursion_depth,
67581 duk_hthread *entry_curr_thread,
67582 duk_instr_t **entry_ptr_curr_pc) {
67583 DUK_ASSERT(thr != NULL);
67584 DUK_CTX_ASSERT_VALID(thr);
67585 DUK_UNREF(idx_retbase);
67586 DUK_UNREF(num_stack_rets);
67587 DUK_UNREF(entry_curr_thread);
67588
67589 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
67590
67591 /* Restore entry thread executor curr_pc stack frame pointer.
67592 * XXX: would be enough to do in error path only, should nest
67593 * cleanly in success path.
67594 */
67595 thr->ptr_curr_pc = entry_ptr_curr_pc;
67596
67597 thr->heap->call_recursion_depth = entry_call_recursion_depth;
67598
67599 /* stack discipline consistency check */
67600 DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
67601
67602 /* A debugger forced interrupt check is not needed here, as
67603 * problematic safe calls are not caused by side effects.
67604 */
67605
67606#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
67607 duk__interrupt_fixup(thr, entry_curr_thread);
67608#endif
67609}
67610
67611DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
67612 duk_safe_call_function func,
67613 void *udata,
67614 duk_idx_t num_stack_args,
67615 duk_idx_t num_stack_rets) {
67616 duk_activation *entry_act;
67617 duk_size_t entry_valstack_bottom_byteoff;
67618#if defined(DUK_USE_ASSERTIONS)
67619 duk_size_t entry_valstack_end_byteoff;
67620 duk_size_t entry_callstack_top;
67621 duk_size_t entry_callstack_preventcount;
67622#endif
67623 duk_int_t entry_call_recursion_depth;
67624 duk_hthread *entry_curr_thread;
67625 duk_uint_fast8_t entry_thread_state;
67626 duk_instr_t **entry_ptr_curr_pc;
67627 duk_jmpbuf *old_jmpbuf_ptr = NULL;
67628 duk_jmpbuf our_jmpbuf;
67629 duk_idx_t idx_retbase;
67630 duk_int_t retval;
67631
67632 DUK_ASSERT(thr != NULL);
67633 DUK_ASSERT(duk_get_top(thr) >= num_stack_args); /* Caller ensures. */
67634
67635 DUK_STATS_INC(thr->heap, stats_safecall_all);
67636
67637 /* Value stack reserve handling: safe call assumes caller has reserved
67638 * space for nrets (assuming optimal unwind processing). Value stack
67639 * reserve is not stored/restored as for normal calls because a safe
67640 * call conceptually happens in the same activation.
67641 */
67642
67643 /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */
67644 entry_act = thr->callstack_curr;
67645 entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
67646#if defined(DUK_USE_ASSERTIONS)
67647 entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
67648 entry_callstack_top = thr->callstack_top;
67649 entry_callstack_preventcount = thr->callstack_preventcount;
67650#endif
67651 entry_call_recursion_depth = thr->heap->call_recursion_depth;
67652 entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */
67653 entry_thread_state = thr->state;
67654 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
67655 idx_retbase = duk_get_top(thr) - num_stack_args; /* not a valid stack index if num_stack_args == 0 */
67656 DUK_ASSERT(idx_retbase >= 0);
67657
67658 DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args); /* Caller ensures. */
67659 DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets); /* Caller ensures. */
67660
67661 /* Cannot portably debug print a function pointer, hence 'func' not printed! */
67662 DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
67663 "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
67664 "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, "
67665 "entry_curr_thread=%p, entry_thread_state=%ld",
67666 (void *) thr,
67667 (long) num_stack_args,
67668 (long) num_stack_rets,
67669 (long) duk_get_top(thr),
67670 (long) idx_retbase,
67671 (long) thr->heap->call_recursion_depth,
67672 (long) thr->heap->call_recursion_limit,
67673 (void *) entry_act,
67674 (long) entry_valstack_bottom_byteoff,
67675 (long) entry_call_recursion_depth,
67676 (void *) entry_curr_thread,
67677 (long) entry_thread_state));
67678
67679 /* Setjmp catchpoint setup. */
67680 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
67681 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
67682
67683 /* Prevent yields for the duration of the safe call. This only
67684 * matters if the executor makes safe calls to functions that
67685 * yield, this doesn't currently happen.
67686 */
67687 thr->callstack_preventcount++;
67688
67689#if defined(DUK_USE_CPP_EXCEPTIONS)
67690 try {
67691#else
67692 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
67693 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
67694 /* Success path. */
67695#endif
67696 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
67697
67698 duk__handle_safe_call_inner(thr,
67699 func,
67700 udata,
67701#if defined(DUK_USE_ASSERTIONS)
67702 entry_valstack_bottom_byteoff,
67703 entry_callstack_top,
67704#endif
67705 entry_curr_thread,
67706 entry_thread_state,
67707 idx_retbase,
67708 num_stack_rets);
67709
67710 DUK_STATS_INC(thr->heap, stats_safecall_nothrow);
67711
67712 /* Either pointer may be NULL (at entry), so don't assert */
67713 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
67714
67715 /* If calls happen inside the safe call, these are restored by
67716 * whatever calls are made. Reserve cannot decrease.
67717 */
67718 DUK_ASSERT(thr->callstack_curr == entry_act);
67719 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67720
67721 retval = DUK_EXEC_SUCCESS;
67722#if defined(DUK_USE_CPP_EXCEPTIONS)
67723 } catch (duk_internal_exception &exc) {
67724 DUK_UNREF(exc);
67725#else
67726 } else {
67727 /* Error path. */
67728#endif
67729 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67730
67731 DUK_STATS_INC(thr->heap, stats_safecall_throw);
67732
67733 duk__handle_safe_call_error(thr,
67734 entry_act,
67735#if defined(DUK_USE_ASSERTIONS)
67736 entry_callstack_top,
67737#endif
67738 entry_curr_thread,
67739 entry_thread_state,
67740 idx_retbase,
67741 num_stack_rets,
67742 entry_valstack_bottom_byteoff,
67743 old_jmpbuf_ptr);
67744
67745 retval = DUK_EXEC_ERROR;
67746 }
67747#if defined(DUK_USE_CPP_EXCEPTIONS)
67748 catch (duk_fatal_exception &exc) {
67749 DUK_D(DUK_DPRINT("rethrow duk_fatal_exception"));
67750 DUK_UNREF(exc);
67751 throw;
67752 } catch (std::exception &exc) {
67753 const char *what = exc.what();
67754 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67755 DUK_STATS_INC(thr->heap, stats_safecall_throw);
67756 if (!what) {
67757 what = "unknown";
67758 }
67759 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
67760 try {
67761 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
67762 DUK_WO_NORETURN(return 0;);
67763 } catch (duk_internal_exception exc) {
67764 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
67765 DUK_UNREF(exc);
67766 duk__handle_safe_call_error(thr,
67767 entry_act,
67768#if defined(DUK_USE_ASSERTIONS)
67769 entry_callstack_top,
67770#endif
67771 entry_curr_thread,
67772 entry_thread_state,
67773 idx_retbase,
67774 num_stack_rets,
67775 entry_valstack_bottom_byteoff,
67776 old_jmpbuf_ptr);
67777 retval = DUK_EXEC_ERROR;
67778 }
67779 } catch (...) {
67780 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
67781 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67782 DUK_STATS_INC(thr->heap, stats_safecall_throw);
67783 try {
67784 DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
67785 DUK_WO_NORETURN(return 0;);
67786 } catch (duk_internal_exception exc) {
67787 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
67788 DUK_UNREF(exc);
67789 duk__handle_safe_call_error(thr,
67790 entry_act,
67791#if defined(DUK_USE_ASSERTIONS)
67792 entry_callstack_top,
67793#endif
67794 entry_curr_thread,
67795 entry_thread_state,
67796 idx_retbase,
67797 num_stack_rets,
67798 entry_valstack_bottom_byteoff,
67799 old_jmpbuf_ptr);
67800 retval = DUK_EXEC_ERROR;
67801 }
67802 }
67803#endif
67804
67805 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
67806
67807 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
67808
67809 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67810 duk__handle_safe_call_shared_unwind(thr,
67811 idx_retbase,
67812 num_stack_rets,
67813#if defined(DUK_USE_ASSERTIONS)
67814 entry_callstack_top,
67815#endif
67816 entry_call_recursion_depth,
67817 entry_curr_thread,
67818 entry_ptr_curr_pc);
67819
67820 /* Restore preventcount. */
67821 thr->callstack_preventcount--;
67822 DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount);
67823
67824 /* Final asserts. */
67825 DUK_ASSERT(thr->callstack_curr == entry_act);
67826 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
67827 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
67828 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
67829 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
67830 DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
67831 DUK_ASSERT(thr->state == entry_thread_state);
67832 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
67833 DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
67834 DUK_ASSERT_LJSTATE_UNSET(thr->heap);
67835
67836 /* Pending side effects. */
67837 DUK_REFZERO_CHECK_FAST(thr);
67838
67839 return retval;
67840}
67841
67842/*
67843 * Property-based call (foo.noSuch()) error setup: replace target function
67844 * on stack top with a hidden Symbol tagged non-callable wrapper object
67845 * holding the error. The error gets thrown in call handling at the
67846 * proper spot to follow ECMAScript semantics.
67847 */
67848
67849#if defined(DUK_USE_VERBOSE_ERRORS)
67850DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_base, duk_tval *tv_key) {
67851 const char *str_targ, *str_key, *str_base;
67852 duk_idx_t entry_top;
67853
67854 entry_top = duk_get_top(thr);
67855
67856 /* [ <nargs> target ] */
67857
67858 /* Must stabilize pointers first. tv_targ is already on stack top. */
67859 duk_push_tval(thr, tv_base);
67860 duk_push_tval(thr, tv_key);
67861
67862 DUK_GC_TORTURE(thr->heap);
67863
67864 duk_push_bare_object(thr);
67865
67866 /* [ <nargs> target base key {} ] */
67867
67868 /* We only push a wrapped error, replacing the call target (at
67869 * idx_func) with the error to ensure side effects come out
67870 * correctly:
67871 * - Property read
67872 * - Call argument evaluation
67873 * - Callability check and error thrown
67874 *
67875 * A hidden Symbol on the wrapper object pushed above is used by
67876 * call handling to figure out the error is to be thrown as is.
67877 * It is CRITICAL that the hidden Symbol can never occur on a
67878 * user visible object that may get thrown.
67879 */
67880
67881#if defined(DUK_USE_PARANOID_ERRORS)
67882 str_targ = duk_get_type_name(thr, -4);
67883 str_key = duk_get_type_name(thr, -2);
67884 str_base = duk_get_type_name(thr, -3);
67885 duk_push_error_object(thr,
67886 DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
67887 "%s not callable (property %s of %s)", str_targ, str_key, str_base);
67888 duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); /* Marker property, reuse _Target. */
67889 /* [ <nargs> target base key { _Target: error } ] */
67890 duk_replace(thr, entry_top - 1);
67891#else
67892 str_targ = duk_push_string_readable(thr, -4);
67893 str_key = duk_push_string_readable(thr, -3);
67894 str_base = duk_push_string_readable(thr, -5);
67895 duk_push_error_object(thr,
67896 DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
67897 "%s not callable (property %s of %s)", str_targ, str_key, str_base);
67898 /* [ <nargs> target base key {} str_targ str_key str_base error ] */
67899 duk_xdef_prop_stridx(thr, -5, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); /* Marker property, reuse _Target. */
67900 /* [ <nargs> target base key { _Target: error } str_targ str_key str_base ] */
67901 duk_swap(thr, -4, entry_top - 1);
67902 /* [ <nargs> { _Target: error } base key target str_targ str_key str_base ] */
67903#endif
67904
67905 /* [ <nregs> { _Target: error } <variable> */
67906 duk_set_top(thr, entry_top);
67907
67908 /* [ <nregs> { _Target: error } */
67909 DUK_ASSERT(!duk_is_callable(thr, -1)); /* Critical so that call handling will throw the error. */
67910}
67911#endif /* DUK_USE_VERBOSE_ERRORS */
67912
67913/* automatic undefs */
67914#undef DUK__AUGMENT_CALL_RELAX_COUNT
67915#undef DUK__CALL_HANDLING_REQUIRE_STACK
67916#line 1 "duk_js_compiler.c"
67917/*
67918 * ECMAScript compiler.
67919 *
67920 * Parses an input string and generates a function template result.
67921 * Compilation may happen in multiple contexts (global code, eval
67922 * code, function code).
67923 *
67924 * The parser uses a traditional top-down recursive parsing for the
67925 * statement level, and an operator precedence based top-down approach
67926 * for the expression level. The attempt is to minimize the C stack
67927 * depth. Bytecode is generated directly without an intermediate
67928 * representation (tree), at the cost of needing two (and sometimes
67929 * three) passes over each function.
67930 *
67931 * The top-down recursive parser functions are named "duk__parse_XXX".
67932 *
67933 * Recursion limits are in key functions to prevent arbitrary C recursion:
67934 * function body parsing, statement parsing, and expression parsing.
67935 *
67936 * See doc/compiler.rst for discussion on the design.
67937 *
67938 * A few typing notes:
67939 *
67940 * - duk_regconst_t: signed, highest bit set (< 0) means constant,
67941 * some call sites use -1 for "none" (equivalent to constant 0x7fffffff)
67942 * - PC values: duk_int_t, negative values used as markers
67943 */
67944
67945/* #include duk_internal.h -> already included */
67946
67947/* If highest bit of a register number is set, it refers to a constant instead.
67948 * When interpreted as a signed value, this means const values are always
67949 * negative (when interpreted as two's complement). For example DUK__ISREG_TEMP()
67950 * uses this approach to avoid an explicit DUK__ISREG() check (the condition is
67951 * logically "'x' is a register AND 'x' >= temp_first").
67952 */
67953#define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER
67954#define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER)
67955#define DUK__ISREG(x) ((x) >= 0)
67956#define DUK__ISCONST(x) ((x) < 0)
67957#define DUK__ISREG_TEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= temp_first && x >= 0 by comparing as signed. */
67958#define DUK__ISREG_NOTTEMP(comp_ctx,x) ((duk_uint32_t) (x) < (duk_uint32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= 0 && x < temp_first by interpreting as unsigned. */
67959#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
67960#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
67961#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
67962#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
67963#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
67964
67965/* Init value set size for array and object literals. */
67966#define DUK__MAX_ARRAY_INIT_VALUES 20
67967#define DUK__MAX_OBJECT_INIT_PAIRS 10
67968
67969/* XXX: hack, remove when const lookup is not O(n) */
67970#define DUK__GETCONST_MAX_CONSTS_CHECK 256
67971
67972/* These limits are based on bytecode limits. Max temps is limited
67973 * by duk_hcompfunc nargs/nregs fields being 16 bits.
67974 */
67975#define DUK__MAX_CONSTS DUK_BC_BC_MAX
67976#define DUK__MAX_FUNCS DUK_BC_BC_MAX
67977#define DUK__MAX_TEMPS 0xffffL
67978
67979/* Initial bytecode size allocation. */
67980#if defined(DUK_USE_PREFER_SIZE)
67981#define DUK__BC_INITIAL_INSTS 16
67982#else
67983#define DUK__BC_INITIAL_INSTS 256
67984#endif
67985
67986#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
67987 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
67988 duk__comp_recursion_increase((comp_ctx)); \
67989 } while (0)
67990
67991#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
67992 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
67993 duk__comp_recursion_decrease((comp_ctx)); \
67994 } while (0)
67995
67996/* Value stack slot limits: these are quite approximate right now, and
67997 * because they overlap in control flow, some could be eliminated.
67998 */
67999#define DUK__COMPILE_ENTRY_SLOTS 8
68000#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
68001#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
68002#define DUK__PARSE_STATEMENTS_SLOTS 16
68003#define DUK__PARSE_EXPR_SLOTS 16
68004
68005/* Temporary structure used to pass a stack allocated region through
68006 * duk_safe_call().
68007 */
68008typedef struct {
68009 duk_small_uint_t flags;
68010 duk_compiler_ctx comp_ctx_alloc;
68011 duk_lexer_point lex_pt_alloc;
68012} duk__compiler_stkstate;
68013
68014/*
68015 * Prototypes
68016 */
68017
68018/* lexing */
68019DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
68020DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
68021DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
68022
68023/* function helpers */
68024DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
68025DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
68026DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg);
68027DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
68028DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
68029
68030/* code emission */
68031DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
68032DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
68033DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
68034DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
68035DUK_LOCAL_DECL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c);
68036DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b);
68037DUK_LOCAL_DECL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c);
68038#if 0 /* unused */
68039DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
68040DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b);
68041#endif
68042DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc);
68043DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc);
68044DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
68045DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
68046DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
68047DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
68048DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
68049DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
68050DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
68051DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
68052DUK_LOCAL_DECL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags);
68053DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
68054DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
68055DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
68056
68057/* ivalue/ispec helpers */
68058DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst);
68059DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68060DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68061DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h);
68062DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
68063DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
68064DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
68065DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
68066DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next);
68067DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
68068DUK_LOCAL_DECL
68069duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
68070 duk_ispec *x,
68071 duk_regconst_t forced_reg,
68072 duk_small_uint_t flags);
68073DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg);
68074DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg);
68075DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68076DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68077DUK_LOCAL_DECL
68078duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
68079 duk_ivalue *x,
68080 duk_regconst_t forced_reg,
68081 duk_small_uint_t flags);
68082DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68083#if 0 /* unused */
68084DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68085#endif
68086DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
68087DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68088DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
68089
68090/* identifier handling */
68091DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
68092DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
68093
68094/* label handling */
68095DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id);
68096DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
68097DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest);
68098DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len);
68099
68100/* top-down expression parser */
68101DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68102DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
68103DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
68104DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
68105
68106/* exprtop is the top level variant which resets nud/led counts */
68107DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68108DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68109
68110/* convenience helpers */
68111#if 0 /* unused */
68112DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68113#endif
68114#if 0 /* unused */
68115DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68116#endif
68117DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
68118DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68119#if 0 /* unused */
68120DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68121#endif
68122DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68123DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68124DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68125#if 0 /* unused */
68126DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68127#endif
68128DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg);
68129DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68130#if 0 /* unused */
68131DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
68132#endif
68133
68134/* expression parsing helpers */
68135DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68136DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68137DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68138
68139/* statement parsing */
68140DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
68141DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
68142DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
68143DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
68144DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68145DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
68146DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
68147DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68148DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68149DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68150DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68151DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
68152DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
68153DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
68154DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after);
68155
68156DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token);
68157DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
68158DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
68159DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
68160
68161#define DUK__FUNC_FLAG_DECL (1 << 0) /* Parsing a function declaration. */
68162#define DUK__FUNC_FLAG_GETSET (1 << 1) /* Parsing an object literal getter/setter. */
68163#define DUK__FUNC_FLAG_METDEF (1 << 2) /* Parsing an object literal method definition shorthand. */
68164#define DUK__FUNC_FLAG_PUSHNAME_PASS1 (1 << 3) /* Push function name when creating template (first pass only). */
68165#define DUK__FUNC_FLAG_USE_PREVTOKEN (1 << 4) /* Use prev_token to start function parsing (workaround for object literal). */
68166
68167/*
68168 * Parser control values for tokens. The token table is ordered by the
68169 * DUK_TOK_XXX defines.
68170 *
68171 * The binding powers are for lbp() use (i.e. for use in led() context).
68172 * Binding powers are positive for typing convenience, and bits at the
68173 * top should be reserved for flags. Binding power step must be higher
68174 * than 1 so that binding power "lbp - 1" can be used for right associative
68175 * operators. Currently a step of 2 is used (which frees one more bit for
68176 * flags).
68177 */
68178
68179/* XXX: actually single step levels would work just fine, clean up */
68180
68181/* binding power "levels" (see doc/compiler.rst) */
68182#define DUK__BP_INVALID 0 /* always terminates led() */
68183#define DUK__BP_EOF 2
68184#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
68185#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
68186#define DUK__BP_COMMA 6
68187#define DUK__BP_ASSIGNMENT 8
68188#define DUK__BP_CONDITIONAL 10
68189#define DUK__BP_LOR 12
68190#define DUK__BP_LAND 14
68191#define DUK__BP_BOR 16
68192#define DUK__BP_BXOR 18
68193#define DUK__BP_BAND 20
68194#define DUK__BP_EQUALITY 22
68195#define DUK__BP_RELATIONAL 24
68196#define DUK__BP_SHIFT 26
68197#define DUK__BP_ADDITIVE 28
68198#define DUK__BP_MULTIPLICATIVE 30
68199#define DUK__BP_EXPONENTIATION 32
68200#define DUK__BP_POSTFIX 34
68201#define DUK__BP_CALL 36
68202#define DUK__BP_MEMBER 38
68203
68204#define DUK__TOKEN_LBP_BP_MASK 0x1f
68205#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
68206#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
68207#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* unused */
68208
68209#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
68210
68211#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
68212#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
68213
68214DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
68215 DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */
68216 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */
68217 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */
68218 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */
68219 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */
68220 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */
68221 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */
68222 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */
68223 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */
68224 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */
68225 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */
68226 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */
68227 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */
68228 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */
68229 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */
68230 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */
68231 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */
68232 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */
68233 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */
68234 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */
68235 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */
68236 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */
68237 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
68238 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
68239 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
68240 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
68241 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
68242 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
68243 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
68244 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
68245 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
68246 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
68247 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
68248 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */
68249 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */
68250 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */
68251 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */
68252 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */
68253 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */
68254 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */
68255 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */
68256 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */
68257 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */
68258 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */
68259 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */
68260 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */
68261 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */
68262 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */
68263 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */
68264 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */
68265 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */
68266 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */
68267 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */
68268 DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */
68269 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */
68270 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */
68271 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */
68272 DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */
68273 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */
68274 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */
68275 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */
68276 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */
68277 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */
68278 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */
68279 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */
68280 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */
68281 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */
68282 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */
68283 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
68284 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
68285 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
68286 DUK__MK_LBP(DUK__BP_EXPONENTIATION), /* DUK_TOK_EXP */
68287 DUK__MK_LBP_FLAGS(DUK__BP_POSTFIX, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_INCREMENT */
68288 DUK__MK_LBP_FLAGS(DUK__BP_POSTFIX, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_DECREMENT */
68289 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
68290 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */
68291 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */
68292 DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */
68293 DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */
68294 DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */
68295 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */
68296 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */
68297 DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */
68298 DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */
68299 DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */
68300 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */
68301 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */
68302 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */
68303 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */
68304 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
68305 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
68306 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
68307 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EXP_EQ */
68308 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
68309 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
68310 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
68311 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
68312 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
68313 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
68314 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
68315 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
68316 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
68317};
68318
68319/*
68320 * Misc helpers
68321 */
68322
68323DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) {
68324 DUK_ASSERT(comp_ctx != NULL);
68325 DUK_ASSERT(comp_ctx->recursion_depth >= 0);
68326 if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
68327 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
68328 DUK_WO_NORETURN(return;);
68329 }
68330 comp_ctx->recursion_depth++;
68331}
68332
68333DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) {
68334 DUK_ASSERT(comp_ctx != NULL);
68335 DUK_ASSERT(comp_ctx->recursion_depth > 0);
68336 comp_ctx->recursion_depth--;
68337}
68338
68339DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
68340 DUK_UNREF(comp_ctx);
68341 DUK_ASSERT(h != NULL);
68342 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
68343}
68344
68345DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
68346 DUK_ASSERT(h != NULL);
68347 return (comp_ctx->curr_func.is_strict &&
68348 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
68349}
68350
68351/*
68352 * Parser duk__advance() token eating functions
68353 */
68354
68355/* XXX: valstack handling is awkward. Add a valstack helper which
68356 * avoids dup():ing; valstack_copy(src, dst)?
68357 */
68358
68359DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
68360 duk_hthread *thr = comp_ctx->thr;
68361 duk_bool_t regexp;
68362
68363 DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0); /* unsigned */
68364 DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
68365
68366 /*
68367 * Use current token to decide whether a RegExp can follow.
68368 *
68369 * We can use either 't' or 't_nores'; the latter would not
68370 * recognize keywords. Some keywords can be followed by a
68371 * RegExp (e.g. "return"), so using 't' is better. This is
68372 * not trivial, see doc/compiler.rst.
68373 */
68374
68375 regexp = 1;
68376 if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
68377 regexp = 0;
68378 }
68379 if (comp_ctx->curr_func.reject_regexp_in_adv) {
68380 comp_ctx->curr_func.reject_regexp_in_adv = 0;
68381 regexp = 0;
68382 }
68383 if (comp_ctx->curr_func.allow_regexp_in_adv) {
68384 comp_ctx->curr_func.allow_regexp_in_adv = 0;
68385 regexp = 1;
68386 }
68387
68388 if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) {
68389 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
68390 (long) expect, (long) comp_ctx->curr_token.t));
68391 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
68392 DUK_WO_NORETURN(return;);
68393 }
68394
68395 /* make current token the previous; need to fiddle with valstack "backing store" */
68396 duk_memcpy(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
68397 duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
68398 duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
68399
68400 /* parse new token */
68401 duk_lexer_parse_js_input_element(&comp_ctx->lex,
68402 &comp_ctx->curr_token,
68403 comp_ctx->curr_func.is_strict,
68404 regexp);
68405
68406 DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
68407 "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
68408 (long) comp_ctx->curr_token.t,
68409 (long) comp_ctx->curr_token.t_nores,
68410 (long) comp_ctx->curr_token.start_line,
68411 (long) comp_ctx->curr_token.lineterm,
68412 (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx),
68413 (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx),
68414 (long) comp_ctx->prev_token.t,
68415 (long) comp_ctx->prev_token.t_nores,
68416 (long) comp_ctx->prev_token.start_line,
68417 (long) comp_ctx->prev_token.lineterm,
68418 (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx),
68419 (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx)));
68420}
68421
68422/* advance, expecting current token to be a specific token; parse next token in regexp context */
68423DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
68424 duk__advance_helper(comp_ctx, expect);
68425}
68426
68427/* advance, whatever the current token is; parse next token in regexp context */
68428DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
68429 duk__advance_helper(comp_ctx, -1);
68430}
68431
68432/*
68433 * Helpers for duk_compiler_func.
68434 */
68435
68436/* init function state: inits valstack allocations */
68437DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
68438 duk_compiler_func *func = &comp_ctx->curr_func;
68439 duk_hthread *thr = comp_ctx->thr;
68440 duk_idx_t entry_top;
68441
68442 entry_top = duk_get_top(thr);
68443
68444 duk_memzero(func, sizeof(*func)); /* intentional overlap with earlier memzero */
68445#if defined(DUK_USE_EXPLICIT_NULL_INIT)
68446 func->h_name = NULL;
68447 func->h_consts = NULL;
68448 func->h_funcs = NULL;
68449 func->h_decls = NULL;
68450 func->h_labelnames = NULL;
68451 func->h_labelinfos = NULL;
68452 func->h_argnames = NULL;
68453 func->h_varmap = NULL;
68454#endif
68455
68456 duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
68457
68458 DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
68459 /* code_idx = entry_top + 0 */
68460
68461 duk_push_bare_array(thr);
68462 func->consts_idx = entry_top + 1;
68463 func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1);
68464 DUK_ASSERT(func->h_consts != NULL);
68465
68466 duk_push_bare_array(thr);
68467 func->funcs_idx = entry_top + 2;
68468 func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2);
68469 DUK_ASSERT(func->h_funcs != NULL);
68470 DUK_ASSERT(func->fnum_next == 0);
68471
68472 duk_push_bare_array(thr);
68473 func->decls_idx = entry_top + 3;
68474 func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3);
68475 DUK_ASSERT(func->h_decls != NULL);
68476
68477 duk_push_bare_array(thr);
68478 func->labelnames_idx = entry_top + 4;
68479 func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4);
68480 DUK_ASSERT(func->h_labelnames != NULL);
68481
68482 duk_push_dynamic_buffer(thr, 0);
68483 func->labelinfos_idx = entry_top + 5;
68484 func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5);
68485 DUK_ASSERT(func->h_labelinfos != NULL);
68486 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
68487
68488 duk_push_bare_array(thr);
68489 func->argnames_idx = entry_top + 6;
68490 func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6);
68491 DUK_ASSERT(func->h_argnames != NULL);
68492
68493 duk_push_bare_object(thr);
68494 func->varmap_idx = entry_top + 7;
68495 func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7);
68496 DUK_ASSERT(func->h_varmap != NULL);
68497}
68498
68499/* reset function state (prepare for pass 2) */
68500DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
68501 duk_compiler_func *func = &comp_ctx->curr_func;
68502 duk_hthread *thr = comp_ctx->thr;
68503
68504 /* reset bytecode buffer but keep current size; pass 2 will
68505 * require same amount or more.
68506 */
68507 DUK_BW_RESET_SIZE(thr, &func->bw_code);
68508
68509 duk_set_length(thr, func->consts_idx, 0);
68510 /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
68511 func->fnum_next = 0;
68512 /* duk_set_length(thr, func->funcs_idx, 0); */
68513 duk_set_length(thr, func->labelnames_idx, 0);
68514 duk_hbuffer_reset(thr, func->h_labelinfos);
68515 /* keep func->h_argnames; it is fixed for all passes */
68516
68517 /* truncated in case pass 3 needed */
68518 duk_push_bare_object(thr);
68519 duk_replace(thr, func->varmap_idx);
68520 func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx);
68521 DUK_ASSERT(func->h_varmap != NULL);
68522}
68523
68524/* cleanup varmap from any null entries, compact it, etc; returns number
68525 * of final entries after cleanup.
68526 */
68527DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
68528 duk_hthread *thr = comp_ctx->thr;
68529 duk_hobject *h_varmap;
68530 duk_hstring *h_key;
68531 duk_tval *tv;
68532 duk_uint32_t i, e_next;
68533 duk_int_t ret;
68534
68535 /* [ ... varmap ] */
68536
68537 h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1);
68538 DUK_ASSERT(h_varmap != NULL);
68539
68540 ret = 0;
68541 e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
68542 for (i = 0; i < e_next; i++) {
68543 h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
68544 if (!h_key) {
68545 continue;
68546 }
68547
68548 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
68549
68550 /* The entries can either be register numbers or 'null' values.
68551 * Thus, no need to DECREF them and get side effects. DECREF'ing
68552 * the keys (strings) can cause memory to be freed but no side
68553 * effects as strings don't have finalizers. This is why we can
68554 * rely on the object properties not changing from underneath us.
68555 */
68556
68557 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
68558 if (!DUK_TVAL_IS_NUMBER(tv)) {
68559 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
68560 DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
68561 DUK_HSTRING_DECREF(thr, h_key);
68562 /* when key is NULL, value is garbage so no need to set */
68563 } else {
68564 ret++;
68565 }
68566 }
68567
68568 duk_compact_m1(thr);
68569
68570 return ret;
68571}
68572
68573/* Convert duk_compiler_func into a function template, leaving the result
68574 * on top of stack.
68575 */
68576/* XXX: awkward and bloated asm -- use faster internal accesses */
68577DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
68578 duk_compiler_func *func = &comp_ctx->curr_func;
68579 duk_hthread *thr = comp_ctx->thr;
68580 duk_hcompfunc *h_res;
68581 duk_hbuffer_fixed *h_data;
68582 duk_size_t consts_count;
68583 duk_size_t funcs_count;
68584 duk_size_t code_count;
68585 duk_size_t code_size;
68586 duk_size_t data_size;
68587 duk_size_t i;
68588 duk_tval *p_const;
68589 duk_hobject **p_func;
68590 duk_instr_t *p_instr;
68591 duk_compiler_instr *q_instr;
68592 duk_tval *tv;
68593 duk_bool_t keep_varmap;
68594 duk_bool_t keep_formals;
68595#if !defined(DUK_USE_DEBUGGER_SUPPORT)
68596 duk_size_t formals_length;
68597#endif
68598
68599 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
68600
68601 /*
68602 * Push result object and init its flags
68603 */
68604
68605 /* Valstack should suffice here, required on function valstack init */
68606
68607 h_res = duk_push_hcompfunc(thr);
68608 DUK_ASSERT(h_res != NULL);
68609 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
68610 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */
68611
68612 if (func->is_function) {
68613 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
68614 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
68615
68616 if (!func->is_arguments_shadowed) {
68617 /* arguments object would be accessible; note that shadowing
68618 * bindings are arguments or function declarations, neither
68619 * of which are deletable, so this is safe.
68620 */
68621
68622 if (func->id_access_arguments || func->may_direct_eval) {
68623 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
68624 "indirectly -> set CREATEARGS"));
68625 DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
68626 }
68627 }
68628 } else if (func->is_eval && func->is_strict) {
68629 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
68630 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
68631 } else {
68632 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
68633 * global code: env is is global env
68634 */
68635 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
68636 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
68637 }
68638
68639#if defined(DUK_USE_FUNC_NAME_PROPERTY)
68640 if (func->is_function && func->is_namebinding && func->h_name != NULL) {
68641 /* Object literal set/get functions have a name (property
68642 * name) but must not have a lexical name binding, see
68643 * test-bug-getset-func-name.js.
68644 */
68645 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
68646 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
68647 }
68648#endif
68649
68650 if (func->is_strict) {
68651 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
68652 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
68653 }
68654
68655 if (func->is_notail) {
68656 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
68657 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
68658 }
68659
68660 if (func->is_constructable) {
68661 DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE"));
68662 DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res);
68663 }
68664
68665 /*
68666 * Build function fixed size 'data' buffer, which contains bytecode,
68667 * constants, and inner function references.
68668 *
68669 * During the building phase 'data' is reachable but incomplete.
68670 * Only incref's occur during building (no refzero or GC happens),
68671 * so the building process is atomic.
68672 */
68673
68674 consts_count = duk_hobject_get_length(thr, func->h_consts);
68675 funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
68676 code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
68677 code_size = code_count * sizeof(duk_instr_t);
68678
68679 data_size = consts_count * sizeof(duk_tval) +
68680 funcs_count * sizeof(duk_hobject *) +
68681 code_size;
68682
68683 DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
68684 "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
68685 (long) consts_count, (long) funcs_count, (long) code_size,
68686 (long) consts_count, (long) sizeof(duk_tval),
68687 (long) funcs_count, (long) sizeof(duk_hobject *),
68688 (long) code_size, (long) data_size));
68689
68690 duk_push_fixed_buffer_nozero(thr, data_size);
68691 h_data = (duk_hbuffer_fixed *) (void *) duk_known_hbuffer(thr, -1);
68692
68693 DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
68694 DUK_HEAPHDR_INCREF(thr, h_data);
68695
68696 p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
68697 for (i = 0; i < consts_count; i++) {
68698 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */
68699 tv = duk_hobject_find_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
68700 DUK_ASSERT(tv != NULL);
68701 DUK_TVAL_SET_TVAL(p_const, tv);
68702 p_const++;
68703 DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
68704
68705 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
68706 }
68707
68708 p_func = (duk_hobject **) p_const;
68709 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func);
68710 for (i = 0; i < funcs_count; i++) {
68711 duk_hobject *h;
68712 DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
68713 tv = duk_hobject_find_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
68714 DUK_ASSERT(tv != NULL);
68715 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
68716 h = DUK_TVAL_GET_OBJECT(tv);
68717 DUK_ASSERT(h != NULL);
68718 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h));
68719 *p_func++ = h;
68720 DUK_HOBJECT_INCREF(thr, h);
68721
68722 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
68723 (void *) h, (duk_heaphdr *) h));
68724 }
68725
68726 p_instr = (duk_instr_t *) p_func;
68727 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr);
68728
68729 /* copy bytecode instructions one at a time */
68730 q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
68731 for (i = 0; i < code_count; i++) {
68732 p_instr[i] = q_instr[i].ins;
68733 }
68734 /* Note: 'q_instr' is still used below */
68735
68736 DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
68737
68738 duk_pop(thr); /* 'data' (and everything in it) is reachable through h_res now */
68739
68740 /*
68741 * Init non-property result fields
68742 *
68743 * 'nregs' controls how large a register frame is allocated.
68744 *
68745 * 'nargs' controls how many formal arguments are written to registers:
68746 * r0, ... r(nargs-1). The remaining registers are initialized to
68747 * undefined.
68748 */
68749
68750 DUK_ASSERT(func->temp_max >= 0);
68751 h_res->nregs = (duk_uint16_t) func->temp_max;
68752 h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
68753 DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
68754#if defined(DUK_USE_DEBUGGER_SUPPORT)
68755 h_res->start_line = (duk_uint32_t) func->min_line;
68756 h_res->end_line = (duk_uint32_t) func->max_line;
68757#endif
68758
68759 /*
68760 * Init object properties
68761 *
68762 * Properties should be added in decreasing order of access frequency.
68763 * (Not very critical for function templates.)
68764 */
68765
68766 DUK_DDD(DUK_DDDPRINT("init function properties"));
68767
68768 /* [ ... res ] */
68769
68770 /* _Varmap: omitted if function is guaranteed not to do a slow path
68771 * identifier access that might be caught by locally declared variables.
68772 * The varmap can also be omitted if it turns out empty of actual
68773 * register mappings after a cleanup. When debugging is enabled, we
68774 * always need the varmap to be able to lookup variables at any point.
68775 */
68776
68777#if defined(DUK_USE_DEBUGGER_SUPPORT)
68778 DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled"));
68779 keep_varmap = 1;
68780#else
68781 if (func->id_access_slow_own || /* directly uses slow accesses that may match own variables */
68782 func->id_access_arguments || /* accesses 'arguments' directly */
68783 func->may_direct_eval || /* may indirectly slow access through a direct eval */
68784 funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
68785 DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions"));
68786 keep_varmap = 1;
68787 } else {
68788 DUK_DD(DUK_DDPRINT("dropping _Varmap"));
68789 keep_varmap = 0;
68790 }
68791#endif
68792
68793 if (keep_varmap) {
68794 duk_int_t num_used;
68795 duk_dup(thr, func->varmap_idx);
68796 num_used = duk__cleanup_varmap(comp_ctx);
68797 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
68798 (duk_tval *) duk_get_tval(thr, -1), (long) num_used));
68799
68800 if (num_used > 0) {
68801 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
68802 } else {
68803 DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add"));
68804 duk_pop(thr);
68805 }
68806 }
68807
68808 /* _Formals: omitted if function is guaranteed not to need a (non-strict)
68809 * arguments object, and _Formals.length matches nargs exactly.
68810 *
68811 * Non-arrow functions can't see an outer function's 'argument' binding
68812 * (because they have their own), but arrow functions can. When arrow
68813 * functions are added, this condition would need to be added:
68814 * inner_arrow_funcs_count > 0 inner arrow functions may access 'arguments'
68815 */
68816#if defined(DUK_USE_DEBUGGER_SUPPORT)
68817 DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled"));
68818 keep_formals = 1;
68819#else
68820 formals_length = duk_get_length(thr, func->argnames_idx);
68821 if (formals_length != (duk_size_t) h_res->nargs) {
68822 /* Nargs not enough for closure .length: keep _Formals regardless
68823 * of its length. Shouldn't happen in practice at the moment.
68824 */
68825 DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs"));
68826 keep_formals = 1;
68827 } else if ((func->id_access_arguments || func->may_direct_eval) &&
68828 (formals_length > 0)) {
68829 /* Direct eval (may access 'arguments') or accesses 'arguments'
68830 * explicitly: keep _Formals unless it is zero length.
68831 */
68832 DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0"));
68833 keep_formals = 1;
68834 } else {
68835 DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added"));
68836 keep_formals = 0;
68837 }
68838#endif
68839
68840 if (keep_formals) {
68841 duk_dup(thr, func->argnames_idx);
68842 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
68843 }
68844
68845 /* name */
68846#if defined(DUK_USE_FUNC_NAME_PROPERTY)
68847 if (func->h_name) {
68848 duk_push_hstring(thr, func->h_name);
68849 DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(thr, -1)));
68850 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
68851 }
68852#endif /* DUK_USE_FUNC_NAME_PROPERTY */
68853
68854 /* _Source */
68855#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
68856 if (0) {
68857 /* XXX: Currently function source code is not stored, as it is not
68858 * required by the standard. Source code should not be stored by
68859 * default (user should enable it explicitly), and the source should
68860 * probably be compressed with a trivial text compressor; average
68861 * compression of 20-30% is quite easy to achieve even with a trivial
68862 * compressor (RLE + backwards lookup).
68863 *
68864 * Debugging needs source code to be useful: sometimes input code is
68865 * not found in files as it may be generated and then eval()'d, given
68866 * by dynamic C code, etc.
68867 *
68868 * Other issues:
68869 *
68870 * - Need tokenizer indices for start and end to substring
68871 * - Always normalize function declaration part?
68872 * - If we keep _Formals, only need to store body
68873 */
68874
68875 /*
68876 * For global or eval code this is straightforward. For functions
68877 * created with the Function constructor we only get the source for
68878 * the body and must manufacture the "function ..." part.
68879 *
68880 * For instance, for constructed functions (v8):
68881 *
68882 * > a = new Function("foo", "bar", "print(foo)");
68883 * [Function]
68884 * > a.toString()
68885 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
68886 *
68887 * Similarly for e.g. getters (v8):
68888 *
68889 * > x = { get a(foo,bar) { print(foo); } }
68890 * { a: [Getter] }
68891 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
68892 * 'function a(foo,bar) { print(foo); }'
68893 */
68894
68895#if 0
68896 duk_push_literal(thr, "XXX");
68897 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
68898#endif
68899 }
68900#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
68901
68902 /* _Pc2line */
68903#if defined(DUK_USE_PC2LINE)
68904 if (1) {
68905 /*
68906 * Size-optimized pc->line mapping.
68907 */
68908
68909 DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
68910 duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
68911 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
68912
68913 /* XXX: if assertions enabled, walk through all valid PCs
68914 * and check line mapping.
68915 */
68916 }
68917#endif /* DUK_USE_PC2LINE */
68918
68919 /* fileName */
68920#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
68921 if (comp_ctx->h_filename) {
68922 /*
68923 * Source filename (or equivalent), for identifying thrown errors.
68924 */
68925
68926 duk_push_hstring(thr, comp_ctx->h_filename);
68927 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
68928 }
68929#endif
68930
68931 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
68932 (duk_tval *) duk_get_tval(thr, -1)));
68933
68934 /*
68935 * Compact the function template.
68936 */
68937
68938 duk_compact_m1(thr);
68939
68940 /*
68941 * Debug dumping
68942 */
68943
68944#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
68945 {
68946 duk_hcompfunc *h;
68947 duk_instr_t *p, *p_start, *p_end;
68948
68949 h = (duk_hcompfunc *) duk_get_hobject(thr, -1);
68950 p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h);
68951 p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h);
68952
68953 p = p_start;
68954 while (p < p_end) {
68955 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!X) a=%ld b=%ld c=%ld",
68956 (long) (p - p_start),
68957 (duk_instr_t) (*p),
68958 (unsigned long) (*p),
68959 (long) DUK_DEC_OP(*p),
68960 (long) DUK_DEC_OP(*p),
68961 (long) DUK_DEC_A(*p),
68962 (long) DUK_DEC_B(*p),
68963 (long) DUK_DEC_C(*p)));
68964 p++;
68965 }
68966 }
68967#endif
68968}
68969
68970/*
68971 * Code emission helpers
68972 *
68973 * Some emission helpers understand the range of target and source reg/const
68974 * values and automatically emit shuffling code if necessary. This is the
68975 * case when the slot in question (A, B, C) is used in the standard way and
68976 * for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ).
68977 *
68978 * The standard way is that:
68979 * - slot A is a target register
68980 * - slot B is a source register/constant
68981 * - slot C is a source register/constant
68982 *
68983 * If a slot is used in a non-standard way the caller must indicate this
68984 * somehow. If a slot is used as a target instead of a source (or vice
68985 * versa), this can be indicated with a flag to trigger proper shuffling
68986 * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
68987 * register/const related at all, the caller must ensure that the raw value
68988 * fits into the corresponding slot so as to not trigger shuffling. The
68989 * caller must set a "no shuffle" flag to ensure compilation fails if
68990 * shuffling were to be triggered because of an internal error.
68991 *
68992 * For slots B and C the raw slot size is 9 bits but one bit is reserved for
68993 * the reg/const indicator. To use the full 9-bit range for a raw value,
68994 * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
68995 * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
68996 *
68997 * There is call handling specific understanding in the A-B-C emitter to
68998 * convert call setup and call instructions into indirect ones if necessary.
68999 */
69000
69001/* Code emission flags, passed in the 'opcode' field. Opcode + flags
69002 * fit into 16 bits for now, so use duk_small_uint_t.
69003 */
69004#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
69005#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
69006#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
69007#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
69008#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
69009#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
69010#define DUK__EMIT_FLAG_BC_REGCONST (1 << 14) /* slots B and C are reg/const */
69011#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
69012
69013/* XXX: macro smaller than call? */
69014DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
69015 duk_compiler_func *func;
69016 func = &comp_ctx->curr_func;
69017 return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
69018}
69019
69020DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
69021 DUK_ASSERT(pc >= 0);
69022 DUK_ASSERT((duk_size_t) pc < (duk_size_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)));
69023 return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
69024}
69025
69026/* emit instruction; could return PC but that's not needed in the majority
69027 * of cases.
69028 */
69029DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
69030#if defined(DUK_USE_PC2LINE)
69031 duk_int_t line;
69032#endif
69033 duk_compiler_instr *instr;
69034
69035 DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
69036 (unsigned long) ins,
69037 (long) comp_ctx->curr_token.start_line,
69038 (long) comp_ctx->prev_token.start_line,
69039 (long) duk__get_current_pc(comp_ctx),
69040 (duk_instr_t) ins));
69041
69042 instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
69043 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
69044
69045#if defined(DUK_USE_PC2LINE)
69046 /* The line number tracking is a bit inconsistent right now, which
69047 * affects debugger accuracy. Mostly call sites emit opcodes when
69048 * they have parsed a token (say a terminating semicolon) and called
69049 * duk__advance(). In this case the line number of the previous
69050 * token is the most accurate one (except in prologue where
69051 * prev_token.start_line is 0). This is probably not 100% correct
69052 * right now.
69053 */
69054 /* approximation, close enough */
69055 line = comp_ctx->prev_token.start_line;
69056 if (line == 0) {
69057 line = comp_ctx->curr_token.start_line;
69058 }
69059#endif
69060
69061 instr->ins = ins;
69062#if defined(DUK_USE_PC2LINE)
69063 instr->line = (duk_uint32_t) line;
69064#endif
69065#if defined(DUK_USE_DEBUGGER_SUPPORT)
69066 if (line < comp_ctx->curr_func.min_line) {
69067 comp_ctx->curr_func.min_line = line;
69068 }
69069 if (line > comp_ctx->curr_func.max_line) {
69070 comp_ctx->curr_func.max_line = line;
69071 }
69072#endif
69073
69074 /* Limit checks for bytecode byte size and line number. */
69075 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
69076 goto fail_bc_limit;
69077 }
69078#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
69079#if defined(DUK_USE_BUFLEN16)
69080 /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
69081 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
69082 goto fail_bc_limit;
69083 }
69084#else
69085 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
69086 goto fail_bc_limit;
69087 }
69088#endif
69089#endif
69090
69091 return;
69092
69093 fail_bc_limit:
69094 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
69095 DUK_WO_NORETURN(return;);
69096}
69097
69098/* Update function min/max line from current token. Needed to improve
69099 * function line range information for debugging, so that e.g. opening
69100 * curly brace is covered by line range even when no opcodes are emitted
69101 * for the line containing the brace.
69102 */
69103DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
69104#if defined(DUK_USE_DEBUGGER_SUPPORT)
69105 duk_int_t line;
69106
69107 line = comp_ctx->curr_token.start_line;
69108 if (line == 0) {
69109 return;
69110 }
69111 if (line < comp_ctx->curr_func.min_line) {
69112 comp_ctx->curr_func.min_line = line;
69113 }
69114 if (line > comp_ctx->curr_func.max_line) {
69115 comp_ctx->curr_func.max_line = line;
69116 }
69117#else
69118 DUK_UNREF(comp_ctx);
69119#endif
69120}
69121
69122DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
69123 duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
69124}
69125
69126/* Important main primitive. */
69127DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) {
69128 duk_instr_t ins = 0;
69129 duk_int_t a_out = -1;
69130 duk_int_t b_out = -1;
69131 duk_int_t c_out = -1;
69132 duk_int_t tmp;
69133 duk_small_uint_t op = op_flags & 0xffU;
69134
69135 DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
69136 (unsigned long) op_flags, (long) a, (long) b, (long) c));
69137
69138 /* We could rely on max temp/const checks: if they don't exceed BC
69139 * limit, nothing here can either (just asserts would be enough).
69140 * Currently we check for the limits, which provides additional
69141 * protection against creating invalid bytecode due to compiler
69142 * bugs.
69143 */
69144
69145 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
69146 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
69147 DUK_ASSERT(DUK__ISREG(a));
69148 DUK_ASSERT(b != -1); /* Not 'none'. */
69149 DUK_ASSERT(c != -1); /* Not 'none'. */
69150
69151 /* Input shuffling happens before the actual operation, while output
69152 * shuffling happens afterwards. Output shuffling decisions are still
69153 * made at the same time to reduce branch clutter; output shuffle decisions
69154 * are recorded into X_out variables.
69155 */
69156
69157 /* Slot A: currently no support for reg/const. */
69158
69159#if defined(DUK_USE_SHUFFLE_TORTURE)
69160 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
69161#else
69162 if (a <= DUK_BC_A_MAX) {
69163#endif
69164 ;
69165 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
69166 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
69167 goto error_outofregs;
69168 } else if (a <= DUK_BC_BC_MAX) {
69169 comp_ctx->curr_func.needs_shuffle = 1;
69170 tmp = comp_ctx->curr_func.shuffle1;
69171 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
69172 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
69173 } else {
69174 /* Output shuffle needed after main operation */
69175 a_out = a;
69176
69177 /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are
69178 * consecutive.
69179 */
69180 DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) ||
69181 (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1));
69182 if (op == DUK_OP_CSVAR) {
69183 /* For CSVAR the limit is one smaller because output shuffle
69184 * must be able to express 'a + 1' in BC.
69185 */
69186 if (a + 1 > DUK_BC_BC_MAX) {
69187 goto error_outofregs;
69188 }
69189 }
69190 }
69191 a = tmp;
69192 } else {
69193 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
69194 goto error_outofregs;
69195 }
69196
69197 /* Slot B: reg/const support, mapped to bit 0 of opcode. */
69198
69199 if ((b & DUK__CONST_MARKER) != 0) {
69200 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
69201 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
69202 b = b & ~DUK__CONST_MARKER;
69203#if defined(DUK_USE_SHUFFLE_TORTURE)
69204 if (0) {
69205#else
69206 if (b <= 0xff) {
69207#endif
69208 if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
69209 /* Opcode follows B/C reg/const convention. */
69210 DUK_ASSERT((op & 0x01) == 0);
69211 ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0); /* const flag for B */
69212 } else {
69213 DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x", op_flags));
69214 }
69215 } else if (b <= DUK_BC_BC_MAX) {
69216 comp_ctx->curr_func.needs_shuffle = 1;
69217 tmp = comp_ctx->curr_func.shuffle2;
69218 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
69219 b = tmp;
69220 } else {
69221 DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
69222 goto error_outofregs;
69223 }
69224 } else {
69225#if defined(DUK_USE_SHUFFLE_TORTURE)
69226 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
69227#else
69228 if (b <= 0xff) {
69229#endif
69230 ;
69231 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
69232 if (b > DUK_BC_B_MAX) {
69233 /* Note: 0xff != DUK_BC_B_MAX */
69234 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
69235 goto error_outofregs;
69236 }
69237 } else if (b <= DUK_BC_BC_MAX) {
69238 comp_ctx->curr_func.needs_shuffle = 1;
69239 tmp = comp_ctx->curr_func.shuffle2;
69240 if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
69241 /* Output shuffle needed after main operation */
69242 b_out = b;
69243 }
69244 if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) {
69245 if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
69246 /* Special handling for MPUTOBJ/MPUTARR shuffling.
69247 * For each, slot B identifies the first register of a range
69248 * of registers, so normal shuffling won't work. Instead,
69249 * an indirect version of the opcode is used.
69250 */
69251 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
69252 duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
69253 DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
69254 DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
69255 op_flags++; /* indirect opcode follows direct */
69256 } else {
69257 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
69258 }
69259 }
69260 b = tmp;
69261 } else {
69262 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
69263 goto error_outofregs;
69264 }
69265 }
69266
69267 /* Slot C: reg/const support, mapped to bit 1 of opcode. */
69268
69269 if ((c & DUK__CONST_MARKER) != 0) {
69270 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
69271 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
69272 c = c & ~DUK__CONST_MARKER;
69273#if defined(DUK_USE_SHUFFLE_TORTURE)
69274 if (0) {
69275#else
69276 if (c <= 0xff) {
69277#endif
69278 if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
69279 /* Opcode follows B/C reg/const convention. */
69280 DUK_ASSERT((op & 0x02) == 0);
69281 ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0); /* const flag for C */
69282 } else {
69283 DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x", op_flags));
69284 }
69285 } else if (c <= DUK_BC_BC_MAX) {
69286 comp_ctx->curr_func.needs_shuffle = 1;
69287 tmp = comp_ctx->curr_func.shuffle3;
69288 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
69289 c = tmp;
69290 } else {
69291 DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
69292 goto error_outofregs;
69293 }
69294 } else {
69295#if defined(DUK_USE_SHUFFLE_TORTURE)
69296 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
69297#else
69298 if (c <= 0xff) {
69299#endif
69300 ;
69301 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
69302 if (c > DUK_BC_C_MAX) {
69303 /* Note: 0xff != DUK_BC_C_MAX */
69304 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
69305 goto error_outofregs;
69306 }
69307 } else if (c <= DUK_BC_BC_MAX) {
69308 comp_ctx->curr_func.needs_shuffle = 1;
69309 tmp = comp_ctx->curr_func.shuffle3;
69310 if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
69311 /* Output shuffle needed after main operation */
69312 c_out = c;
69313 } else {
69314 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
69315 }
69316 c = tmp;
69317 } else {
69318 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
69319 goto error_outofregs;
69320 }
69321 }
69322
69323 /* Main operation */
69324
69325 DUK_ASSERT(a >= DUK_BC_A_MIN);
69326 DUK_ASSERT(a <= DUK_BC_A_MAX);
69327 DUK_ASSERT(b >= DUK_BC_B_MIN);
69328 DUK_ASSERT(b <= DUK_BC_B_MAX);
69329 DUK_ASSERT(c >= DUK_BC_C_MIN);
69330 DUK_ASSERT(c <= DUK_BC_C_MAX);
69331
69332 ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
69333 duk__emit(comp_ctx, ins);
69334
69335 /* NEXTENUM needs a jump slot right after the main instruction.
69336 * When the JUMP is taken, output spilling is not needed so this
69337 * workaround is possible. The jump slot PC is exceptionally
69338 * plumbed through comp_ctx to minimize call sites.
69339 */
69340 if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
69341 comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
69342 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
69343 }
69344
69345 /* Output shuffling: only one output register is realistically possible.
69346 *
69347 * (Zero would normally be an OK marker value: if the target register
69348 * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
69349 * this is no longer true, so use -1 as a marker instead.)
69350 */
69351
69352 if (a_out >= 0) {
69353 DUK_ASSERT(b_out < 0);
69354 DUK_ASSERT(c_out < 0);
69355 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
69356
69357 if (op == DUK_OP_CSVAR) {
69358 /* Special handling for CSVAR shuffling. The variable lookup
69359 * results in a <value, this binding> pair in successive
69360 * registers so use two shuffle registers and two output
69361 * loads. (In practice this is dead code because temp/const
69362 * limit is reached first.)
69363 */
69364 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1));
69365 }
69366 } else if (b_out >= 0) {
69367 DUK_ASSERT(a_out < 0);
69368 DUK_ASSERT(c_out < 0);
69369 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
69370 } else if (c_out >= 0) {
69371 DUK_ASSERT(b_out < 0);
69372 DUK_ASSERT(c_out < 0);
69373 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
69374 }
69375
69376 return;
69377
69378 error_outofregs:
69379 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
69380 DUK_WO_NORETURN(return;);
69381}
69382
69383/* For many of the helpers below it'd be technically correct to add
69384 * "no shuffle" flags for parameters passed in as zero. For example,
69385 * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and
69386 * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags. However, since the
69387 * C value is 0, it'll never get shuffled so adding the flag is just
69388 * unnecessary additional code. This is unfortunately not true for
69389 * "shuffle torture" mode which needs special handling.
69390 */
69391
69392DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) {
69393#if defined(DUK_USE_SHUFFLE_TORTURE)
69394 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C;
69395#endif
69396 duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
69397}
69398
69399DUK_LOCAL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c) {
69400#if defined(DUK_USE_SHUFFLE_TORTURE)
69401 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
69402#endif
69403 duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c);
69404}
69405
69406#if 0 /* unused */
69407DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
69408#if defined(DUK_USE_SHUFFLE_TORTURE)
69409 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C;
69410#endif
69411 duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
69412}
69413#endif
69414
69415#if 0 /* unused */
69416DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) {
69417#if defined(DUK_USE_SHUFFLE_TORTURE)
69418 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C;
69419#endif
69420 duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0);
69421}
69422#endif
69423
69424DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc) {
69425 duk_instr_t ins;
69426 duk_int_t tmp;
69427
69428 /* allow caller to give a const number with the DUK__CONST_MARKER */
69429 DUK_ASSERT(bc != -1); /* Not 'none'. */
69430 bc = bc & (~DUK__CONST_MARKER);
69431
69432 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
69433 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
69434 DUK_ASSERT(bc >= DUK_BC_BC_MIN);
69435 DUK_ASSERT(bc <= DUK_BC_BC_MAX);
69436 DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
69437
69438 if (bc <= DUK_BC_BC_MAX) {
69439 ;
69440 } else {
69441 /* No BC shuffling now. */
69442 goto error_outofregs;
69443 }
69444
69445#if defined(DUK_USE_SHUFFLE_TORTURE)
69446 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
69447#else
69448 if (a <= DUK_BC_A_MAX) {
69449#endif
69450 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
69451 duk__emit(comp_ctx, ins);
69452 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
69453 goto error_outofregs;
69454 } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) {
69455 comp_ctx->curr_func.needs_shuffle = 1;
69456 tmp = comp_ctx->curr_func.shuffle1;
69457 duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
69458 op_flags |= DUK_BC_CALL_FLAG_INDIRECT;
69459 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
69460 duk__emit(comp_ctx, ins);
69461 } else if (a <= DUK_BC_BC_MAX) {
69462 comp_ctx->curr_func.needs_shuffle = 1;
69463 tmp = comp_ctx->curr_func.shuffle1;
69464 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
69465 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
69466 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
69467 duk__emit(comp_ctx, ins);
69468 } else {
69469 duk__emit(comp_ctx, ins);
69470 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
69471 }
69472 } else {
69473 goto error_outofregs;
69474 }
69475 return;
69476
69477 error_outofregs:
69478 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
69479 DUK_WO_NORETURN(return;);
69480}
69481
69482DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) {
69483#if defined(DUK_USE_SHUFFLE_TORTURE)
69484 op |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
69485#endif
69486 duk__emit_a_bc(comp_ctx, op, 0, bc);
69487}
69488
69489DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
69490 duk_instr_t ins;
69491
69492 DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */
69493 DUK_ASSERT(op <= DUK_BC_OP_MAX);
69494 DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
69495 DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
69496 DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
69497 DUK_ASSERT(abc != -1); /* Not 'none'. */
69498
69499 if (abc <= DUK_BC_ABC_MAX) {
69500 ;
69501 } else {
69502 goto error_outofregs;
69503 }
69504 ins = DUK_ENC_OP_ABC(op, abc);
69505 DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!X) abc=%ld (%!I)",
69506 (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
69507 (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
69508 (long) abc, (duk_instr_t) ins));
69509 duk__emit(comp_ctx, ins);
69510 return;
69511
69512 error_outofregs:
69513 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
69514 DUK_WO_NORETURN(return;);
69515}
69516
69517DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
69518 /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
69519 * would only shuffle once (instead of twice). The current code works
69520 * though, and has a smaller compiler footprint.
69521 */
69522
69523 if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
69524 (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
69525 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
69526 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
69527 } else {
69528 duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
69529 duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
69530 DUK_ASSERT(lo >= 0);
69531 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
69532 (long) reg, (long) val, (long) hi, (long) lo));
69533 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
69534 duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
69535 }
69536}
69537
69538DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
69539 duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
69540}
69541
69542#if defined(DUK_USE_SHUFFLE_TORTURE)
69543/* Used by duk__emit*() calls so that we don't shuffle the loadints that
69544 * are needed to handle indirect opcodes.
69545 */
69546DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
69547 duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
69548}
69549#else
69550DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
69551 /* When torture not enabled, can just use the same helper because
69552 * 'reg' won't get spilled.
69553 */
69554 DUK_ASSERT(reg <= DUK_BC_A_MAX);
69555 duk__emit_load_int32(comp_ctx, reg, val);
69556}
69557#endif
69558
69559DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
69560 duk_int_t curr_pc;
69561 duk_int_t offset;
69562
69563 curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
69564 offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
69565 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
69566 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
69567 duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
69568}
69569
69570DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
69571 duk_int_t ret;
69572
69573 ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
69574 duk__emit_op_only(comp_ctx, DUK_OP_JUMP);
69575 return ret;
69576}
69577
69578/* Insert an empty jump in the middle of code emitted earlier. This is
69579 * currently needed for compiling for-in.
69580 */
69581DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
69582#if defined(DUK_USE_PC2LINE)
69583 duk_int_t line;
69584#endif
69585 duk_compiler_instr *instr;
69586 duk_size_t offset;
69587
69588 DUK_ASSERT(jump_pc >= 0);
69589 offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr);
69590 instr = (duk_compiler_instr *) (void *)
69591 DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
69592 &comp_ctx->curr_func.bw_code,
69593 offset,
69594 sizeof(duk_compiler_instr));
69595
69596#if defined(DUK_USE_PC2LINE)
69597 line = comp_ctx->curr_token.start_line; /* approximation, close enough */
69598#endif
69599 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
69600#if defined(DUK_USE_PC2LINE)
69601 instr->line = (duk_uint32_t) line;
69602#endif
69603
69604 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
69605 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
69606 goto fail_bc_limit;
69607 }
69608 return;
69609
69610 fail_bc_limit:
69611 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
69612 DUK_WO_NORETURN(return;);
69613}
69614
69615/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
69616 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
69617 */
69618DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
69619 duk_compiler_instr *instr;
69620 duk_int_t offset;
69621
69622 /* allow negative PCs, behave as a no-op */
69623 if (jump_pc < 0) {
69624 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
69625 (long) jump_pc, (long) target_pc));
69626 return;
69627 }
69628 DUK_ASSERT(jump_pc >= 0);
69629
69630 /* XXX: range assert */
69631 instr = duk__get_instr_ptr(comp_ctx, jump_pc);
69632 DUK_ASSERT(instr != NULL);
69633
69634 /* XXX: range assert */
69635 offset = target_pc - jump_pc - 1;
69636
69637 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
69638 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
69639 (long) jump_pc, (long) target_pc, (long) offset));
69640}
69641
69642DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
69643 duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
69644}
69645
69646DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) {
69647 duk_compiler_instr *instr;
69648
69649 DUK_ASSERT(DUK__ISREG(reg_catch));
69650
69651 instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
69652 DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
69653 DUK_ASSERT(instr != NULL);
69654 if (const_varname & DUK__CONST_MARKER) {
69655 /* Have a catch variable. */
69656 const_varname = const_varname & (~DUK__CONST_MARKER);
69657 if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
69658 /* Catch attempts to use out-of-range reg/const. Without this
69659 * check Duktape 0.12.0 could generate invalid code which caused
69660 * an assert failure on execution. This error is triggered e.g.
69661 * for functions with a lot of constants and a try-catch statement.
69662 * Shuffling or opcode semantics change is needed to fix the issue.
69663 * See: test-bug-trycatch-many-constants.js.
69664 */
69665 DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
69666 (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
69667 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
69668 DUK_WO_NORETURN(return;);
69669 }
69670 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
69671 } else {
69672 /* No catch variable, e.g. a try-finally; replace LDCONST with
69673 * NOP to avoid a bogus LDCONST.
69674 */
69675 instr->ins = DUK_ENC_OP(DUK_OP_NOP);
69676 }
69677
69678 instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
69679 DUK_ASSERT(instr != NULL);
69680 DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
69681 DUK_ASSERT(flags <= DUK_BC_A_MAX);
69682 instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
69683}
69684
69685DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
69686 duk_small_uint_t op;
69687
69688 op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C;
69689 duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
69690}
69691
69692DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
69693 duk_small_uint_t op;
69694
69695 op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C;
69696 duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
69697}
69698
69699DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
69700 duk__emit_op_only(comp_ctx, DUK_OP_INVALID);
69701}
69702
69703/*
69704 * Peephole optimizer for finished bytecode.
69705 *
69706 * Does not remove opcodes; currently only straightens out unconditional
69707 * jump chains which are generated by several control structures.
69708 */
69709
69710DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
69711 duk_compiler_instr *bc;
69712 duk_small_uint_t iter;
69713 duk_int_t i, n;
69714 duk_int_t count_opt;
69715
69716 bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
69717#if defined(DUK_USE_BUFLEN16)
69718 /* No need to assert, buffer size maximum is 0xffff. */
69719#else
69720 DUK_ASSERT((duk_size_t) DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr) <= (duk_size_t) DUK_INT_MAX); /* bytecode limits */
69721#endif
69722 n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
69723
69724 for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
69725 count_opt = 0;
69726
69727 for (i = 0; i < n; i++) {
69728 duk_instr_t ins;
69729 duk_int_t target_pc1;
69730 duk_int_t target_pc2;
69731
69732 ins = bc[i].ins;
69733 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
69734 continue;
69735 }
69736
69737 target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
69738 DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
69739 DUK_ASSERT(target_pc1 >= 0);
69740 DUK_ASSERT(target_pc1 < n);
69741
69742 /* Note: if target_pc1 == i, we'll optimize a jump to itself.
69743 * This does not need to be checked for explicitly; the case
69744 * is rare and max iter breaks us out.
69745 */
69746
69747 ins = bc[target_pc1].ins;
69748 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
69749 continue;
69750 }
69751
69752 target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
69753
69754 DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
69755 (long) i, (long) target_pc1, (long) target_pc2));
69756
69757 bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
69758
69759 count_opt++;
69760 }
69761
69762 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
69763
69764 if (count_opt == 0) {
69765 break;
69766 }
69767 }
69768}
69769
69770/*
69771 * Intermediate value helpers
69772 */
69773
69774/* Flags for intermediate value coercions. A flag for using a forced reg
69775 * is not needed, the forced_reg argument suffices and generates better
69776 * code (it is checked as it is used).
69777 */
69778/* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented
69779 * by ispec/ivalue operations.
69780 */
69781#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
69782#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
69783#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
69784
69785/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */
69786
69787#if 0 /* enable manually for dumping */
69788#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
69789#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
69790
69791DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
69792 DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
69793 (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
69794 duk_get_tval(comp_ctx->thr, x->valstack_idx)));
69795}
69796DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
69797 DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
69798 "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
69799 "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
69800 (long) x->t, (long) x->op,
69801 (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
69802 duk_get_tval(comp_ctx->thr, x->x1.valstack_idx),
69803 (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
69804 duk_get_tval(comp_ctx->thr, x->x2.valstack_idx)));
69805}
69806#else
69807#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
69808#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
69809#endif
69810
69811DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) {
69812 x->t = DUK_IVAL_PLAIN;
69813 x->x1.t = DUK_ISPEC_REGCONST;
69814 x->x1.regconst = regconst;
69815}
69816
69817DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
69818 x->t = DUK_IVAL_PLAIN;
69819 x->x1.t = DUK_ISPEC_VALUE;
69820 duk_replace(comp_ctx->thr, x->x1.valstack_idx);
69821}
69822
69823DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
69824 x->t = DUK_IVAL_VAR;
69825 x->x1.t = DUK_ISPEC_VALUE;
69826 duk_replace(comp_ctx->thr, x->x1.valstack_idx);
69827}
69828
69829DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) {
69830 DUK_ASSERT(h != NULL);
69831 duk_push_hstring(comp_ctx->thr, h);
69832 duk__ivalue_var_fromstack(comp_ctx, x);
69833}
69834
69835DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
69836 dst->t = src->t;
69837 dst->regconst = src->regconst;
69838 duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx);
69839}
69840
69841DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
69842 dst->t = src->t;
69843 dst->op = src->op;
69844 dst->x1.t = src->x1.t;
69845 dst->x1.regconst = src->x1.regconst;
69846 dst->x2.t = src->x2.t;
69847 dst->x2.regconst = src->x2.regconst;
69848 duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx);
69849 duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx);
69850}
69851
69852DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
69853 duk_regconst_t res;
69854
69855 res = comp_ctx->curr_func.temp_next;
69856 comp_ctx->curr_func.temp_next += num;
69857
69858 if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
69859 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
69860 DUK_WO_NORETURN(return 0;);
69861 }
69862
69863 /* maintain highest 'used' temporary, needed to figure out nregs of function */
69864 if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
69865 comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
69866 }
69867
69868 return res;
69869}
69870
69871DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
69872 return duk__alloctemps(comp_ctx, 1);
69873}
69874
69875DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) {
69876 comp_ctx->curr_func.temp_next = temp_next;
69877 if (temp_next > comp_ctx->curr_func.temp_max) {
69878 comp_ctx->curr_func.temp_max = temp_next;
69879 }
69880}
69881
69882/* get const for value at valstack top */
69883DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
69884 duk_hthread *thr = comp_ctx->thr;
69885 duk_compiler_func *f = &comp_ctx->curr_func;
69886 duk_tval *tv1;
69887 duk_int_t i, n, n_check;
69888
69889 n = (duk_int_t) duk_get_length(thr, f->consts_idx);
69890
69891 tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
69892 DUK_ASSERT(tv1 != NULL);
69893
69894#if defined(DUK_USE_FASTINT)
69895 /* Explicit check for fastint downgrade. */
69896 DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1);
69897#endif
69898
69899 /* Sanity workaround for handling functions with a large number of
69900 * constants at least somewhat reasonably. Otherwise checking whether
69901 * we already have the constant would grow very slow (as it is O(N^2)).
69902 */
69903 n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
69904 for (i = 0; i < n_check; i++) {
69905 duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
69906
69907 /* Strict equality is NOT enough, because we cannot use the same
69908 * constant for e.g. +0 and -0.
69909 */
69910 if (duk_js_samevalue(tv1, tv2)) {
69911 DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
69912 (duk_tval *) tv1, (long) i));
69913 duk_pop(thr);
69914 return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER;
69915 }
69916 }
69917
69918 if (n > DUK__MAX_CONSTS) {
69919 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
69920 DUK_WO_NORETURN(return 0;);
69921 }
69922
69923 DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
69924 (duk_tval *) tv1, (long) n));
69925 (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n); /* invalidates tv1, tv2 */
69926 return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER;
69927}
69928
69929DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) {
69930#if defined(DUK_USE_REFERENCE_COUNTING)
69931 duk_compiler_func *f = &comp_ctx->curr_func;
69932 duk_bool_t ret;
69933
69934 DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
69935 (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc);
69936 ret = !duk_is_number(comp_ctx->thr, -1); /* now only number/string, so conservative check */
69937 duk_pop(comp_ctx->thr);
69938 return ret;
69939#else
69940 DUK_UNREF(comp_ctx);
69941 DUK_UNREF(rc);
69942 DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
69943 return 0;
69944#endif
69945}
69946
69947/* Get the value represented by an duk_ispec to a register or constant.
69948 * The caller can control the result by indicating whether or not:
69949 *
69950 * (1) a constant is allowed (sometimes the caller needs the result to
69951 * be in a register)
69952 *
69953 * (2) a temporary register is required (usually when caller requires
69954 * the register to be safely mutable; normally either a bound
69955 * register or a temporary register are both OK)
69956 *
69957 * (3) a forced register target needs to be used
69958 *
69959 * Bytecode may be emitted to generate the necessary value. The return
69960 * value is either a register or a constant.
69961 */
69962
69963DUK_LOCAL
69964duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
69965 duk_ispec *x,
69966 duk_regconst_t forced_reg,
69967 duk_small_uint_t flags) {
69968 duk_hthread *thr = comp_ctx->thr;
69969
69970 DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
69971 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
69972 (long) x->t,
69973 (long) x->regconst,
69974 (duk_tval *) duk_get_tval(thr, x->valstack_idx),
69975 (long) forced_reg,
69976 (unsigned long) flags,
69977 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
69978 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
69979 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
69980
69981 switch (x->t) {
69982 case DUK_ISPEC_VALUE: {
69983 duk_tval *tv;
69984
69985 tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx);
69986 DUK_ASSERT(tv != NULL);
69987
69988 switch (DUK_TVAL_GET_TAG(tv)) {
69989 case DUK_TAG_UNDEFINED: {
69990 /* Note: although there is no 'undefined' literal, undefined
69991 * values can occur during compilation as a result of e.g.
69992 * the 'void' operator.
69993 */
69994 duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
69995 duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest);
69996 return dest;
69997 }
69998 case DUK_TAG_NULL: {
69999 duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70000 duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest);
70001 return dest;
70002 }
70003 case DUK_TAG_BOOLEAN: {
70004 duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70005 duk__emit_bc(comp_ctx,
70006 (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE),
70007 dest);
70008 return dest;
70009 }
70010 case DUK_TAG_POINTER: {
70011 DUK_UNREACHABLE();
70012 break;
70013 }
70014 case DUK_TAG_STRING: {
70015 duk_hstring *h;
70016 duk_regconst_t dest;
70017 duk_regconst_t constidx;
70018
70019 h = DUK_TVAL_GET_STRING(tv);
70020 DUK_UNREF(h);
70021 DUK_ASSERT(h != NULL);
70022
70023#if 0 /* XXX: to be implemented? */
70024 /* Use special opcodes to load short strings */
70025 if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
70026 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
70027 } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
70028 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
70029 }
70030#endif
70031 duk_dup(thr, x->valstack_idx);
70032 constidx = duk__getconst(comp_ctx);
70033
70034 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
70035 return constidx;
70036 }
70037
70038 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70039 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
70040 return dest;
70041 }
70042 case DUK_TAG_OBJECT: {
70043 DUK_UNREACHABLE();
70044 break;
70045 }
70046 case DUK_TAG_BUFFER: {
70047 DUK_UNREACHABLE();
70048 break;
70049 }
70050 case DUK_TAG_LIGHTFUNC: {
70051 DUK_UNREACHABLE();
70052 break;
70053 }
70054#if defined(DUK_USE_FASTINT)
70055 case DUK_TAG_FASTINT:
70056#endif
70057 default: {
70058 /* number */
70059 duk_regconst_t dest;
70060 duk_regconst_t constidx;
70061 duk_double_t dval;
70062 duk_int32_t ival;
70063
70064 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
70065 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
70066 dval = DUK_TVAL_GET_NUMBER(tv);
70067
70068 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
70069 /* A number can be loaded either through a constant, using
70070 * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
70071 * LDINT+LDINTX is not if the constant is used multiple times.
70072 * Currently always prefer LDINT+LDINTX over a double constant.
70073 */
70074
70075 if (duk_is_whole_get_int32_nonegzero(dval, &ival)) {
70076 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70077 duk__emit_load_int32(comp_ctx, dest, ival);
70078 return dest;
70079 }
70080 }
70081
70082 duk_dup(thr, x->valstack_idx);
70083 constidx = duk__getconst(comp_ctx);
70084
70085 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
70086 return constidx;
70087 } else {
70088 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70089 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
70090 return dest;
70091 }
70092 }
70093 } /* end switch */
70094 goto fail_internal; /* never here */
70095 }
70096 case DUK_ISPEC_REGCONST: {
70097 if (forced_reg >= 0) {
70098 if (DUK__ISCONST(x->regconst)) {
70099 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
70100 } else if (x->regconst != forced_reg) {
70101 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
70102 } else {
70103 ; /* already in correct reg */
70104 }
70105 return forced_reg;
70106 }
70107
70108 DUK_ASSERT(forced_reg < 0);
70109 if (DUK__ISCONST(x->regconst)) {
70110 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
70111 duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
70112 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
70113 return dest;
70114 }
70115 return x->regconst;
70116 }
70117
70118 DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst));
70119 if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) {
70120 duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
70121 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
70122 return dest;
70123 }
70124 return x->regconst;
70125 }
70126 default: {
70127 break; /* never here */
70128 }
70129 }
70130
70131 fail_internal:
70132 DUK_ERROR_INTERNAL(thr);
70133 DUK_WO_NORETURN(return 0;);
70134}
70135
70136DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) {
70137 DUK_ASSERT(forced_reg >= 0);
70138 (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
70139}
70140
70141/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
70142 * arithmetic operations, property access, or variable access bytecode.
70143 * The duk_ivalue argument ('x') is converted into a plain value as a
70144 * side effect.
70145 */
70146DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) {
70147 duk_hthread *thr = comp_ctx->thr;
70148
70149 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
70150 "forced_reg=%ld",
70151 (long) x->t, (long) x->op,
70152 (long) x->x1.t, (long) x->x1.regconst,
70153 (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
70154 (long) x->x2.t, (long) x->x2.regconst,
70155 (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
70156 (long) forced_reg));
70157
70158 switch (x->t) {
70159 case DUK_IVAL_PLAIN: {
70160 return;
70161 }
70162 /* XXX: support unary arithmetic ivalues (useful?) */
70163 case DUK_IVAL_ARITH: {
70164 duk_regconst_t arg1;
70165 duk_regconst_t arg2;
70166 duk_regconst_t dest;
70167 duk_tval *tv1;
70168 duk_tval *tv2;
70169
70170 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
70171
70172 /* inline arithmetic check for constant values */
70173 /* XXX: use the exactly same arithmetic function here as in executor */
70174 if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
70175 tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx);
70176 tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx);
70177 DUK_ASSERT(tv1 != NULL);
70178 DUK_ASSERT(tv2 != NULL);
70179
70180 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
70181 (duk_tval *) tv1,
70182 (duk_tval *) tv2));
70183
70184 if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
70185 duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
70186 duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
70187 duk_double_t d3;
70188 duk_bool_t accept_fold = 1;
70189
70190 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
70191 (double) d1, (double) d2, (long) x->op));
70192 switch (x->op) {
70193 case DUK_OP_ADD: {
70194 d3 = d1 + d2;
70195 break;
70196 }
70197 case DUK_OP_SUB: {
70198 d3 = d1 - d2;
70199 break;
70200 }
70201 case DUK_OP_MUL: {
70202 d3 = d1 * d2;
70203 break;
70204 }
70205 case DUK_OP_DIV: {
70206 /* Division-by-zero is undefined
70207 * behavior, so rely on a helper.
70208 */
70209 d3 = duk_double_div(d1, d2);
70210 break;
70211 }
70212 case DUK_OP_EXP: {
70213 d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
70214 break;
70215 }
70216 default: {
70217 d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */
70218 accept_fold = 0;
70219 break;
70220 }
70221 }
70222
70223 if (accept_fold) {
70224 duk_double_union du;
70225 du.d = d3;
70226 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
70227 d3 = du.d;
70228
70229 x->t = DUK_IVAL_PLAIN;
70230 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
70231 DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */
70232 return;
70233 }
70234 } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
70235 /* Inline string concatenation. No need to check for
70236 * symbols, as all inputs are valid ECMAScript strings.
70237 */
70238 duk_dup(thr, x->x1.valstack_idx);
70239 duk_dup(thr, x->x2.valstack_idx);
70240 duk_concat(thr, 2);
70241 duk_replace(thr, x->x1.valstack_idx);
70242 x->t = DUK_IVAL_PLAIN;
70243 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
70244 return;
70245 }
70246 }
70247
70248 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
70249 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
70250
70251 /* If forced reg, use it as destination. Otherwise try to
70252 * use either coerced ispec if it is a temporary.
70253 */
70254 if (forced_reg >= 0) {
70255 dest = forced_reg;
70256 } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
70257 dest = arg1;
70258 } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
70259 dest = arg2;
70260 } else {
70261 dest = DUK__ALLOCTEMP(comp_ctx);
70262 }
70263
70264 DUK_ASSERT(DUK__ISREG(dest));
70265 duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2);
70266
70267 duk__ivalue_regconst(x, dest);
70268 return;
70269 }
70270 case DUK_IVAL_PROP: {
70271 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
70272 duk_regconst_t arg1;
70273 duk_regconst_t arg2;
70274 duk_regconst_t dest;
70275
70276 /* Need a short reg/const, does not have to be a mutable temp. */
70277 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
70278 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
70279
70280 /* Pick a destination register. If either base value or key
70281 * happens to be a temp value, reuse it as the destination.
70282 *
70283 * XXX: The temp must be a "mutable" one, i.e. such that no
70284 * other expression is using it anymore. Here this should be
70285 * the case because the value of a property access expression
70286 * is neither the base nor the key, but the lookup result.
70287 */
70288
70289 if (forced_reg >= 0) {
70290 dest = forced_reg;
70291 } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
70292 dest = arg1;
70293 } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
70294 dest = arg2;
70295 } else {
70296 dest = DUK__ALLOCTEMP(comp_ctx);
70297 }
70298
70299 duk__emit_a_b_c(comp_ctx,
70300 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
70301 dest,
70302 arg1,
70303 arg2);
70304
70305 duk__ivalue_regconst(x, dest);
70306 return;
70307 }
70308 case DUK_IVAL_VAR: {
70309 /* x1 must be a string */
70310 duk_regconst_t dest;
70311 duk_regconst_t reg_varbind;
70312 duk_regconst_t rc_varname;
70313
70314 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
70315
70316 duk_dup(thr, x->x1.valstack_idx);
70317 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
70318 duk__ivalue_regconst(x, reg_varbind);
70319 } else {
70320 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
70321 duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname);
70322 duk__ivalue_regconst(x, dest);
70323 }
70324 return;
70325 }
70326 case DUK_IVAL_NONE:
70327 default: {
70328 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
70329 break;
70330 }
70331 }
70332
70333 DUK_ERROR_INTERNAL(thr);
70334 DUK_WO_NORETURN(return;);
70335}
70336
70337/* evaluate to plain value, no forced register (temp/bound reg both ok) */
70338DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70339 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
70340}
70341
70342/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
70343DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70344 duk_regconst_t temp;
70345
70346 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
70347 * restore next temp state.
70348 */
70349 temp = DUK__GETTEMP(comp_ctx);
70350 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
70351 DUK__SETTEMP(comp_ctx, temp);
70352}
70353
70354/* Coerce an duk_ivalue to a register or constant; result register may
70355 * be a temp or a bound register.
70356 *
70357 * The duk_ivalue argument ('x') is converted into a regconst as a
70358 * side effect.
70359 */
70360DUK_LOCAL
70361duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
70362 duk_ivalue *x,
70363 duk_regconst_t forced_reg,
70364 duk_small_uint_t flags) {
70365 duk_hthread *thr = comp_ctx->thr;
70366 duk_regconst_t reg;
70367 DUK_UNREF(thr);
70368
70369 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
70370 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
70371 (long) x->t, (long) x->op,
70372 (long) x->x1.t, (long) x->x1.regconst,
70373 (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
70374 (long) x->x2.t, (long) x->x2.regconst,
70375 (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
70376 (long) forced_reg,
70377 (unsigned long) flags,
70378 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
70379 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
70380 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
70381
70382 /* first coerce to a plain value */
70383 duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
70384 DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
70385
70386 /* then to a register */
70387 reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
70388 duk__ivalue_regconst(x, reg);
70389
70390 return reg;
70391}
70392
70393DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70394 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
70395}
70396
70397#if 0 /* unused */
70398DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70399 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
70400}
70401#endif
70402
70403DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
70404 DUK_ASSERT(forced_reg >= 0);
70405 (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
70406}
70407
70408DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70409 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
70410}
70411
70412DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
70413 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
70414}
70415
70416/* The issues below can be solved with better flags */
70417
70418/* XXX: many operations actually want toforcedtemp() -- brand new temp? */
70419/* XXX: need a toplain_ignore() which will only coerce a value to a temp
70420 * register if it might have a side effect. Side-effect free values do not
70421 * need to be coerced.
70422 */
70423
70424/*
70425 * Identifier handling
70426 */
70427
70428DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
70429 duk_hthread *thr = comp_ctx->thr;
70430 duk_hstring *h_varname;
70431 duk_regconst_t ret;
70432
70433 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
70434 (duk_tval *) duk_get_tval(thr, -1)));
70435
70436 /*
70437 * Special name handling
70438 */
70439
70440 h_varname = duk_known_hstring(thr, -1);
70441
70442 if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
70443 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
70444 comp_ctx->curr_func.id_access_arguments = 1;
70445 }
70446
70447 /*
70448 * Inside one or more 'with' statements fall back to slow path always.
70449 * (See e.g. test-stmt-with.js.)
70450 */
70451
70452 if (comp_ctx->curr_func.with_depth > 0) {
70453 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
70454 goto slow_path_own;
70455 }
70456
70457 /*
70458 * Any catch bindings ("catch (e)") also affect identifier binding.
70459 *
70460 * Currently, the varmap is modified for the duration of the catch
70461 * clause to ensure any identifier accesses with the catch variable
70462 * name will use slow path.
70463 */
70464
70465 duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
70466 if (duk_is_number(thr, -1)) {
70467 ret = duk_to_int(thr, -1);
70468 duk_pop(thr);
70469 } else {
70470 duk_pop(thr);
70471 if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) {
70472 DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap"));
70473 goto slow_path_own;
70474 } else {
70475 /* In this case we're doing a variable lookup that doesn't
70476 * match our own variables, so _Varmap won't be needed at
70477 * run time.
70478 */
70479 DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap"));
70480 goto slow_path_notown;
70481 }
70482 }
70483
70484 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
70485 return ret;
70486
70487 slow_path_notown:
70488 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable"));
70489
70490 comp_ctx->curr_func.id_access_slow = 1;
70491 return (duk_regconst_t) -1;
70492
70493 slow_path_own:
70494 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable"));
70495
70496 comp_ctx->curr_func.id_access_slow = 1;
70497 comp_ctx->curr_func.id_access_slow_own = 1;
70498 return (duk_regconst_t) -1;
70499}
70500
70501/* Lookup an identifier name in the current varmap, indicating whether the
70502 * identifier is register-bound and if not, allocating a constant for the
70503 * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
70504 * also check (out_reg_varbind >= 0) to check whether or not identifier is
70505 * register bound. The caller must NOT use out_rc_varname at all unless
70506 * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
70507 * is unsigned and doesn't have a "unused" / none value.
70508 */
70509DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
70510 duk_hthread *thr = comp_ctx->thr;
70511 duk_regconst_t reg_varbind;
70512 duk_regconst_t rc_varname;
70513
70514 /* [ ... varname ] */
70515
70516 duk_dup_top(thr);
70517 reg_varbind = duk__lookup_active_register_binding(comp_ctx);
70518
70519 if (reg_varbind >= 0) {
70520 *out_reg_varbind = reg_varbind;
70521 *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
70522 duk_pop(thr);
70523 return 1;
70524 } else {
70525 rc_varname = duk__getconst(comp_ctx);
70526 *out_reg_varbind = -1;
70527 *out_rc_varname = rc_varname;
70528 return 0;
70529 }
70530}
70531
70532/*
70533 * Label handling
70534 *
70535 * Labels are initially added with flags prohibiting both break and continue.
70536 * When the statement type is finally uncovered (after potentially multiple
70537 * labels), all the labels are updated to allow/prohibit break and continue.
70538 */
70539
70540DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
70541 duk_hthread *thr = comp_ctx->thr;
70542 duk_size_t n;
70543 duk_size_t new_size;
70544 duk_uint8_t *p;
70545 duk_labelinfo *li_start, *li;
70546
70547 /* Duplicate (shadowing) labels are not allowed, except for the empty
70548 * labels (which are used as default labels for switch and iteration
70549 * statements).
70550 *
70551 * We could also allow shadowing of non-empty pending labels without any
70552 * other issues than breaking the required label shadowing requirements
70553 * of the E5 specification, see Section 12.12.
70554 */
70555
70556 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
70557 li_start = (duk_labelinfo *) (void *) p;
70558 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
70559 n = (duk_size_t) (li - li_start);
70560
70561 while (li > li_start) {
70562 li--;
70563
70564 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
70565 DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
70566 DUK_WO_NORETURN(return;);
70567 }
70568 }
70569
70570 duk_push_hstring(thr, h_label);
70571 DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
70572 (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
70573
70574 new_size = (n + 1) * sizeof(duk_labelinfo);
70575 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
70576 /* XXX: slack handling, slow now */
70577
70578 /* relookup after possible realloc */
70579 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
70580 li_start = (duk_labelinfo *) (void *) p;
70581 DUK_UNREF(li_start); /* silence scan-build warning */
70582 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
70583 li--;
70584
70585 /* Labels can be used for iteration statements but also for other statements,
70586 * in particular a label can be used for a block statement. All cases of a
70587 * named label accept a 'break' so that flag is set here. Iteration statements
70588 * also allow 'continue', so that flag is updated when we figure out the
70589 * statement type.
70590 */
70591
70592 li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
70593 li->label_id = label_id;
70594 li->h_label = h_label;
70595 li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */
70596 li->pc_label = pc_label;
70597
70598 DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
70599 (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
70600 (long) li->catch_depth, (long) li->pc_label));
70601}
70602
70603/* Update all labels with matching label_id. */
70604DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
70605 duk_uint8_t *p;
70606 duk_labelinfo *li_start, *li;
70607
70608 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
70609 li_start = (duk_labelinfo *) (void *) p;
70610 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
70611
70612 /* Match labels starting from latest; once label_id no longer matches, we can
70613 * safely exit without checking the rest of the labels (only the topmost labels
70614 * are ever updated).
70615 */
70616 while (li > li_start) {
70617 li--;
70618
70619 if (li->label_id != label_id) {
70620 break;
70621 }
70622
70623 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
70624 (void *) li, (long) label_id, (long) flags));
70625
70626 li->flags = flags;
70627 }
70628}
70629
70630/* Lookup active label information. Break/continue distinction is necessary to handle switch
70631 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
70632 *
70633 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
70634 * iteration and switch statements) can. A break will match the closest unlabelled or labelled
70635 * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
70636 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
70637 * be duplicated, the continue cannot match any valid label outside the switch.
70638 *
70639 * A side effect of these rules is that a LABEL statement related to a switch should never actually
70640 * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
70641 * continue slot of the switch's LABEL statement.
70642 */
70643
70644/* XXX: awkward, especially the bunch of separate output values -> output struct? */
70645DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) {
70646 duk_hthread *thr = comp_ctx->thr;
70647 duk_uint8_t *p;
70648 duk_labelinfo *li_start, *li_end, *li;
70649 duk_bool_t match = 0;
70650
70651 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
70652 (duk_heaphdr *) h_label, (long) is_break));
70653
70654 DUK_UNREF(thr);
70655
70656 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
70657 li_start = (duk_labelinfo *) (void *) p;
70658 li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
70659 li = li_end;
70660
70661 /* Match labels starting from latest label because there can be duplicate empty
70662 * labels in the label set.
70663 */
70664 while (li > li_start) {
70665 li--;
70666
70667 if (li->h_label != h_label) {
70668 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
70669 (long) (li - li_start),
70670 (duk_heaphdr *) li->h_label,
70671 (duk_heaphdr *) h_label));
70672 continue;
70673 }
70674
70675 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
70676 (long) (li - li_start), (duk_heaphdr *) h_label));
70677
70678 /* currently all labels accept a break, so no explicit check for it now */
70679 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
70680
70681 if (is_break) {
70682 /* break matches always */
70683 match = 1;
70684 break;
70685 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
70686 /* iteration statements allow continue */
70687 match = 1;
70688 break;
70689 } else {
70690 /* continue matched this label -- we can only continue if this is the empty
70691 * label, for which duplication is allowed, and thus there is hope of
70692 * finding a match deeper in the label stack.
70693 */
70694 if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
70695 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
70696 DUK_WO_NORETURN(return;);
70697 } else {
70698 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
70699 "allow a continue -> continue lookup deeper in label stack"));
70700 }
70701 }
70702 }
70703 /* XXX: match flag is awkward, rework */
70704 if (!match) {
70705 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
70706 DUK_WO_NORETURN(return;);
70707 }
70708
70709 DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
70710 (duk_heaphdr *) h_label, (long) li->label_id,
70711 (long) li->catch_depth, (long) li->pc_label));
70712
70713 *out_label_id = li->label_id;
70714 *out_label_catch_depth = li->catch_depth;
70715 *out_label_pc = li->pc_label;
70716 *out_is_closest = (li == li_end - 1);
70717}
70718
70719DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) {
70720 duk_hthread *thr = comp_ctx->thr;
70721
70722 duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len);
70723 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len);
70724}
70725
70726/*
70727 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
70728 *
70729 * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
70730 * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
70731 * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
70732 */
70733
70734/* object literal key tracking flags */
70735#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
70736#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
70737#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
70738
70739DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
70740 duk_hthread *thr = comp_ctx->thr;
70741 duk_regconst_t reg_obj; /* result reg */
70742 duk_regconst_t reg_temp; /* temp reg */
70743 duk_regconst_t temp_start; /* temp reg value for start of loop */
70744 duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
70745 duk_small_uint_t num_values; /* number of values in current MPUTARR set */
70746 duk_uarridx_t curr_idx; /* current (next) array index */
70747 duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
70748 duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
70749 duk_bool_t require_comma; /* next loop requires a comma */
70750#if !defined(DUK_USE_PREFER_SIZE)
70751 duk_int_t pc_newarr;
70752 duk_compiler_instr *instr;
70753#endif
70754
70755 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
70756 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
70757
70758 max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
70759
70760 reg_obj = DUK__ALLOCTEMP(comp_ctx);
70761#if !defined(DUK_USE_PREFER_SIZE)
70762 pc_newarr = duk__get_current_pc(comp_ctx);
70763#endif
70764 duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */
70765 temp_start = DUK__GETTEMP(comp_ctx);
70766
70767 /*
70768 * Emit initializers in sets of maximum max_init_values.
70769 * Corner cases such as single value initializers do not have
70770 * special handling now.
70771 *
70772 * Elided elements must not be emitted as 'undefined' values,
70773 * because such values would be enumerable (which is incorrect).
70774 * Also note that trailing elisions must be reflected in the
70775 * length of the final array but cause no elements to be actually
70776 * inserted.
70777 */
70778
70779 curr_idx = 0;
70780 init_idx = 0; /* tracks maximum initialized index + 1 */
70781 start_idx = 0;
70782 require_comma = 0;
70783
70784 for (;;) {
70785 num_values = 0;
70786 DUK__SETTEMP(comp_ctx, temp_start);
70787
70788 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
70789 break;
70790 }
70791
70792 for (;;) {
70793 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
70794 /* the outer loop will recheck and exit */
70795 break;
70796 }
70797
70798 /* comma check */
70799 if (require_comma) {
70800 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
70801 /* comma after a value, expected */
70802 duk__advance(comp_ctx);
70803 require_comma = 0;
70804 continue;
70805 } else {
70806 goto syntax_error;
70807 }
70808 } else {
70809 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
70810 /* elision - flush */
70811 curr_idx++;
70812 duk__advance(comp_ctx);
70813 /* if num_values > 0, MPUTARR emitted by outer loop after break */
70814 break;
70815 }
70816 }
70817 /* else an array initializer element */
70818
70819 /* initial index */
70820 if (num_values == 0) {
70821 start_idx = curr_idx;
70822 reg_temp = DUK__ALLOCTEMP(comp_ctx);
70823 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
70824 }
70825
70826 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
70827 DUK__SETTEMP(comp_ctx, reg_temp);
70828 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
70829 DUK__SETTEMP(comp_ctx, reg_temp + 1);
70830
70831 num_values++;
70832 curr_idx++;
70833 require_comma = 1;
70834
70835 if (num_values >= max_init_values) {
70836 /* MPUTARR emitted by outer loop */
70837 break;
70838 }
70839 }
70840
70841 if (num_values > 0) {
70842 /* - A is a source register (it's not a write target, but used
70843 * to identify the target object) but can be shuffled.
70844 * - B cannot be shuffled normally because it identifies a range
70845 * of registers, the emitter has special handling for this
70846 * (the "no shuffle" flag must not be set).
70847 * - C is a non-register number and cannot be shuffled, but
70848 * never needs to be.
70849 */
70850 duk__emit_a_b_c(comp_ctx,
70851 DUK_OP_MPUTARR |
70852 DUK__EMIT_FLAG_NO_SHUFFLE_C |
70853 DUK__EMIT_FLAG_A_IS_SOURCE,
70854 reg_obj,
70855 temp_start,
70856 (duk_regconst_t) (num_values + 1));
70857 init_idx = start_idx + num_values;
70858
70859 /* num_values and temp_start reset at top of outer loop */
70860 }
70861 }
70862
70863 /* Update initil size for NEWARR, doesn't need to be exact and is
70864 * capped at A field limit.
70865 */
70866#if !defined(DUK_USE_PREFER_SIZE)
70867 instr = duk__get_instr_ptr(comp_ctx, pc_newarr);
70868 instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx);
70869#endif
70870
70871 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
70872 duk__advance(comp_ctx);
70873
70874 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
70875 (long) curr_idx, (long) init_idx));
70876
70877 /* trailing elisions? */
70878 if (curr_idx > init_idx) {
70879 /* yes, must set array length explicitly */
70880 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
70881 reg_temp = DUK__ALLOCTEMP(comp_ctx);
70882 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
70883 duk__emit_a_bc(comp_ctx,
70884 DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE,
70885 reg_obj,
70886 reg_temp);
70887 }
70888
70889 DUK__SETTEMP(comp_ctx, temp_start);
70890
70891 duk__ivalue_regconst(res, reg_obj);
70892 return;
70893
70894 syntax_error:
70895 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
70896 DUK_WO_NORETURN(return;);
70897}
70898
70899typedef struct {
70900 duk_regconst_t reg_obj;
70901 duk_regconst_t temp_start;
70902 duk_small_uint_t num_pairs;
70903 duk_small_uint_t num_total_pairs;
70904} duk__objlit_state;
70905
70906DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) {
70907 if (st->num_pairs > 0) {
70908 /* - A is a source register (it's not a write target, but used
70909 * to identify the target object) but can be shuffled.
70910 * - B cannot be shuffled normally because it identifies a range
70911 * of registers, the emitter has special handling for this
70912 * (the "no shuffle" flag must not be set).
70913 * - C is a non-register number and cannot be shuffled, but
70914 * never needs to be.
70915 */
70916 DUK_ASSERT(st->num_pairs > 0);
70917 duk__emit_a_b_c(comp_ctx,
70918 DUK_OP_MPUTOBJ |
70919 DUK__EMIT_FLAG_NO_SHUFFLE_C |
70920 DUK__EMIT_FLAG_A_IS_SOURCE,
70921 st->reg_obj,
70922 st->temp_start,
70923 (duk_regconst_t) (st->num_pairs * 2));
70924 st->num_total_pairs += st->num_pairs;
70925 st->num_pairs = 0;
70926 }
70927 DUK__SETTEMP(comp_ctx, st->temp_start);
70928}
70929
70930DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) {
70931 if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) {
70932 /* same handling for identifiers and strings */
70933 DUK_ASSERT(tok->str1 != NULL);
70934 duk_push_hstring(comp_ctx->thr, tok->str1);
70935 } else if (tok->t == DUK_TOK_NUMBER) {
70936 /* numbers can be loaded as numbers and coerced on the fly */
70937 duk_push_number(comp_ctx->thr, tok->num);
70938 } else {
70939 return 1; /* error */
70940 }
70941
70942 duk__ivalue_plain_fromstack(comp_ctx, res);
70943 DUK__SETTEMP(comp_ctx, reg_temp + 1);
70944 duk__ivalue_toforcedreg(comp_ctx, res, reg_temp);
70945 DUK__SETTEMP(comp_ctx, reg_temp + 1);
70946 return 0;
70947}
70948
70949DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
70950 duk_hthread *thr = comp_ctx->thr;
70951 duk__objlit_state st;
70952 duk_regconst_t reg_temp; /* temp reg */
70953 duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
70954 duk_bool_t first; /* first value: comma must not precede the value */
70955 duk_bool_t is_set, is_get; /* temps */
70956#if !defined(DUK_USE_PREFER_SIZE)
70957 duk_int_t pc_newobj;
70958 duk_compiler_instr *instr;
70959#endif
70960
70961 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
70962
70963 max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
70964
70965 st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */
70966 st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */
70967 st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */
70968 st.num_total_pairs = 0; /* number of key/value pairs emitted overall */
70969
70970#if !defined(DUK_USE_PREFER_SIZE)
70971 pc_newobj = duk__get_current_pc(comp_ctx);
70972#endif
70973 duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj);
70974
70975 /*
70976 * Emit initializers in sets of maximum max_init_pairs keys.
70977 * Setter/getter is handled separately and terminates the
70978 * current set of initializer values. Corner cases such as
70979 * single value initializers do not have special handling now.
70980 */
70981
70982 first = 1;
70983 for (;;) {
70984 /*
70985 * ES5 and ES2015+ provide a lot of different PropertyDefinition
70986 * formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer.
70987 *
70988 * PropertyName can be IdentifierName (includes reserved words), a string
70989 * literal, or a number literal. Note that IdentifierName allows 'get' and
70990 * 'set' too, so we need to look ahead to the next token to distinguish:
70991 *
70992 * { get : 1 }
70993 *
70994 * and
70995 *
70996 * { get foo() { return 1 } }
70997 * { get get() { return 1 } } // 'get' as getter propertyname
70998 *
70999 * Finally, a trailing comma is allowed.
71000 *
71001 * Key name is coerced to string at compile time (and ends up as a
71002 * a string constant) even for numeric keys (e.g. "{1:'foo'}").
71003 * These could be emitted using e.g. LDINT, but that seems hardly
71004 * worth the effort and would increase code size.
71005 */
71006
71007 DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld",
71008 (long) comp_ctx->curr_token.t));
71009
71010 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
71011 break;
71012 }
71013
71014 if (first) {
71015 first = 0;
71016 } else {
71017 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
71018 goto syntax_error;
71019 }
71020 duk__advance(comp_ctx);
71021 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
71022 /* trailing comma followed by rcurly */
71023 break;
71024 }
71025 }
71026
71027 /* Advance to get one step of lookup. */
71028 duk__advance(comp_ctx);
71029
71030 /* Flush current MPUTOBJ if enough many pairs gathered. */
71031 if (st.num_pairs >= max_init_pairs) {
71032 duk__objlit_flush_keys(comp_ctx, &st);
71033 DUK_ASSERT(st.num_pairs == 0);
71034 }
71035
71036 /* Reset temp register state and reserve reg_temp and
71037 * reg_temp + 1 for handling the current property.
71038 */
71039 DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs);
71040 reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
71041
71042 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
71043 * currently treats them always like ordinary identifiers (DUK_TOK_GET
71044 * and DUK_TOK_SET are unused). They need to be detected based on the
71045 * identifier string content.
71046 */
71047
71048 is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
71049 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
71050 is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
71051 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
71052 if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
71053 /* getter/setter */
71054 duk_int_t fnum;
71055
71056 duk__objlit_flush_keys(comp_ctx, &st);
71057 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); /* 2 regs are guaranteed to be allocated w.r.t. temp_max */
71058 reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
71059
71060 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) {
71061 goto syntax_error;
71062 }
71063
71064 /* curr_token = get/set name */
71065 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET);
71066
71067 duk__emit_a_bc(comp_ctx,
71068 DUK_OP_CLOSURE,
71069 st.temp_start + 1,
71070 (duk_regconst_t) fnum);
71071
71072 /* Slot C is used in a non-standard fashion (range of regs),
71073 * emitter code has special handling for it (must not set the
71074 * "no shuffle" flag).
71075 */
71076 duk__emit_a_bc(comp_ctx,
71077 (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE,
71078 st.reg_obj,
71079 st.temp_start); /* temp_start+0 = key, temp_start+1 = closure */
71080
71081 DUK_ASSERT(st.num_pairs == 0); /* temp state is reset on next loop */
71082#if defined(DUK_USE_ES6)
71083 } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
71084 (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) {
71085 duk_bool_t load_rc;
71086
71087 load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp);
71088 DUK_UNREF(load_rc);
71089 DUK_ASSERT(load_rc == 0); /* always succeeds because token is identifier */
71090
71091 duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1);
71092 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1);
71093 duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1);
71094
71095 st.num_pairs++;
71096 } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER ||
71097 comp_ctx->prev_token.t == DUK_TOK_STRING ||
71098 comp_ctx->prev_token.t == DUK_TOK_NUMBER) &&
71099 comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
71100 duk_int_t fnum;
71101
71102 /* Parsing-wise there's a small hickup here: the token parsing
71103 * state is one step too advanced for the function parse helper
71104 * compared to other cases. The current solution is an extra
71105 * flag to indicate whether function parsing should use the
71106 * current or the previous token to starting parsing from.
71107 */
71108
71109 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
71110 goto syntax_error;
71111 }
71112
71113 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF);
71114
71115 duk__emit_a_bc(comp_ctx,
71116 DUK_OP_CLOSURE,
71117 reg_temp + 1,
71118 (duk_regconst_t) fnum);
71119
71120 st.num_pairs++;
71121#endif /* DUK_USE_ES6 */
71122 } else {
71123#if defined(DUK_USE_ES6)
71124 if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) {
71125 /* ES2015 computed property name. Executor ToPropertyKey()
71126 * coerces the key at runtime.
71127 */
71128 DUK__SETTEMP(comp_ctx, reg_temp);
71129 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp);
71130 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
71131
71132 /* XXX: If next token is '(' we're dealing with
71133 * the method shorthand with a computed name,
71134 * e.g. { [Symbol.for('foo')](a,b) {} }. This
71135 * form is not yet supported and causes a
71136 * SyntaxError on the DUK_TOK_COLON check below.
71137 */
71138 }
71139 else
71140#endif /* DUK_USE_ES6 */
71141 {
71142 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
71143 goto syntax_error;
71144 }
71145 }
71146
71147 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
71148
71149 DUK__SETTEMP(comp_ctx, reg_temp + 1);
71150 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/);
71151
71152 st.num_pairs++;
71153 }
71154 } /* property loop */
71155
71156 /* Flush remaining properties. */
71157 duk__objlit_flush_keys(comp_ctx, &st);
71158 DUK_ASSERT(st.num_pairs == 0);
71159 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);
71160
71161 /* Update initial size for NEWOBJ. The init size doesn't need to be
71162 * exact as the purpose is just to avoid object resizes in common
71163 * cases. The size is capped to field A limit, and will be too high
71164 * if the object literal contains duplicate keys (this is harmless but
71165 * increases memory traffic if the object is compacted later on).
71166 */
71167#if !defined(DUK_USE_PREFER_SIZE)
71168 instr = duk__get_instr_ptr(comp_ctx, pc_newobj);
71169 instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs);
71170#endif
71171
71172 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
71173 duk__advance(comp_ctx); /* No RegExp after object literal. */
71174
71175 duk__ivalue_regconst(res, st.reg_obj);
71176 return;
71177
71178 syntax_error:
71179 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
71180 DUK_WO_NORETURN(return;);
71181}
71182
71183/* Parse argument list. Arguments are written to temps starting from
71184 * "next temp". Returns number of arguments parsed. Expects left paren
71185 * to be already eaten, and eats the right paren before returning.
71186 */
71187DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
71188 duk_int_t nargs = 0;
71189 duk_regconst_t reg_temp;
71190
71191 /* Note: expect that caller has already eaten the left paren */
71192
71193 DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
71194 (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
71195
71196 for (;;) {
71197 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
71198 break;
71199 }
71200 if (nargs > 0) {
71201 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
71202 }
71203
71204 /* We want the argument expression value to go to "next temp"
71205 * without additional moves. That should almost always be the
71206 * case, but we double check after expression parsing.
71207 *
71208 * This is not the cleanest possible approach.
71209 */
71210
71211 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
71212 DUK__SETTEMP(comp_ctx, reg_temp);
71213
71214 /* binding power must be high enough to NOT allow comma expressions directly */
71215 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */
71216
71217 DUK__SETTEMP(comp_ctx, reg_temp + 1);
71218 nargs++;
71219
71220 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
71221 }
71222
71223 /* eat the right paren */
71224 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */
71225
71226 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
71227
71228 return nargs;
71229}
71230
71231DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
71232 /* empty expressions can be detected conveniently with nud/led counts */
71233 return (comp_ctx->curr_func.nud_count == 0) &&
71234 (comp_ctx->curr_func.led_count == 0);
71235}
71236
71237DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
71238 duk_hthread *thr = comp_ctx->thr;
71239 duk_token *tk;
71240 duk_regconst_t temp_at_entry;
71241 duk_small_uint_t tok;
71242 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
71243
71244 /*
71245 * ctx->prev_token token to process with duk__expr_nud()
71246 * ctx->curr_token updated by caller
71247 *
71248 * Note: the token in the switch below has already been eaten.
71249 */
71250
71251 temp_at_entry = DUK__GETTEMP(comp_ctx);
71252
71253 comp_ctx->curr_func.nud_count++;
71254
71255 tk = &comp_ctx->prev_token;
71256 tok = tk->t;
71257 res->t = DUK_IVAL_NONE;
71258
71259 DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
71260 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
71261
71262 switch (tok) {
71263
71264 /* PRIMARY EXPRESSIONS */
71265
71266 case DUK_TOK_THIS: {
71267 duk_regconst_t reg_temp;
71268 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71269 duk__emit_bc(comp_ctx,
71270 DUK_OP_LDTHIS,
71271 reg_temp);
71272 duk__ivalue_regconst(res, reg_temp);
71273 return;
71274 }
71275 case DUK_TOK_IDENTIFIER: {
71276 duk__ivalue_var_hstring(comp_ctx, res, tk->str1);
71277 return;
71278 }
71279 case DUK_TOK_NULL: {
71280 duk_push_null(thr);
71281 goto plain_value;
71282 }
71283 case DUK_TOK_TRUE: {
71284 duk_push_true(thr);
71285 goto plain_value;
71286 }
71287 case DUK_TOK_FALSE: {
71288 duk_push_false(thr);
71289 goto plain_value;
71290 }
71291 case DUK_TOK_NUMBER: {
71292 duk_push_number(thr, tk->num);
71293 goto plain_value;
71294 }
71295 case DUK_TOK_STRING: {
71296 DUK_ASSERT(tk->str1 != NULL);
71297 duk_push_hstring(thr, tk->str1);
71298 goto plain_value;
71299 }
71300 case DUK_TOK_REGEXP: {
71301#if defined(DUK_USE_REGEXP_SUPPORT)
71302 duk_regconst_t reg_temp;
71303 duk_regconst_t rc_re_bytecode; /* const */
71304 duk_regconst_t rc_re_source; /* const */
71305
71306 DUK_ASSERT(tk->str1 != NULL);
71307 DUK_ASSERT(tk->str2 != NULL);
71308
71309 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
71310 (duk_heaphdr *) tk->str1,
71311 (duk_heaphdr *) tk->str2));
71312
71313 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71314 duk_push_hstring(thr, tk->str1);
71315 duk_push_hstring(thr, tk->str2);
71316
71317 /* [ ... pattern flags ] */
71318
71319 duk_regexp_compile(thr);
71320
71321 /* [ ... escaped_source bytecode ] */
71322
71323 rc_re_bytecode = duk__getconst(comp_ctx);
71324 rc_re_source = duk__getconst(comp_ctx);
71325
71326 duk__emit_a_b_c(comp_ctx,
71327 DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST,
71328 reg_temp /*a*/,
71329 rc_re_bytecode /*b*/,
71330 rc_re_source /*c*/);
71331
71332 duk__ivalue_regconst(res, reg_temp);
71333 return;
71334#else /* DUK_USE_REGEXP_SUPPORT */
71335 goto syntax_error;
71336#endif /* DUK_USE_REGEXP_SUPPORT */
71337 }
71338 case DUK_TOK_LBRACKET: {
71339 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
71340 duk__nud_array_literal(comp_ctx, res);
71341 return;
71342 }
71343 case DUK_TOK_LCURLY: {
71344 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
71345 duk__nud_object_literal(comp_ctx, res);
71346 return;
71347 }
71348 case DUK_TOK_LPAREN: {
71349 duk_bool_t prev_allow_in;
71350
71351 comp_ctx->curr_func.paren_level++;
71352 prev_allow_in = comp_ctx->curr_func.allow_in;
71353 comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
71354
71355 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
71356
71357 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* No RegExp after parenthesized expression. */
71358 comp_ctx->curr_func.allow_in = prev_allow_in;
71359 comp_ctx->curr_func.paren_level--;
71360 return;
71361 }
71362
71363 /* MEMBER/NEW/CALL EXPRESSIONS */
71364
71365 case DUK_TOK_NEW: {
71366 /*
71367 * Parsing an expression starting with 'new' is tricky because
71368 * there are multiple possible productions deriving from
71369 * LeftHandSideExpression which begin with 'new'.
71370 *
71371 * We currently resort to one-token lookahead to distinguish the
71372 * cases. Hopefully this is correct. The binding power must be
71373 * such that parsing ends at an LPAREN (CallExpression) but not at
71374 * a PERIOD or LBRACKET (MemberExpression).
71375 *
71376 * See doc/compiler.rst for discussion on the parsing approach,
71377 * and testcases/test-dev-new.js for a bunch of documented tests.
71378 */
71379
71380 duk_regconst_t reg_target;
71381 duk_int_t nargs;
71382
71383 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
71384
71385 reg_target = DUK__ALLOCTEMPS(comp_ctx, 2);
71386
71387#if defined(DUK_USE_ES6)
71388 if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) {
71389 /* new.target */
71390 DUK_DDD(DUK_DDDPRINT("new.target"));
71391 duk__advance(comp_ctx);
71392 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER ||
71393 !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target")) {
71394 goto syntax_error_newtarget;
71395 }
71396 if (comp_ctx->curr_func.is_global) {
71397 goto syntax_error_newtarget;
71398 }
71399 duk__advance(comp_ctx);
71400 duk__emit_bc(comp_ctx,
71401 DUK_OP_NEWTARGET,
71402 reg_target);
71403 duk__ivalue_regconst(res, reg_target);
71404 return;
71405 }
71406#endif /* DUK_USE_ES6 */
71407
71408 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
71409 duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1); /* default instance */
71410 DUK__SETTEMP(comp_ctx, reg_target + 2);
71411
71412 /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which
71413 * makes the error message worse than for obj.noSuch().
71414 */
71415
71416 if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
71417 /* 'new' MemberExpression Arguments */
71418 DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
71419 duk__advance(comp_ctx);
71420 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */
71421 /* right paren eaten */
71422 } else {
71423 /* 'new' MemberExpression */
71424 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
71425 nargs = 0;
71426 }
71427
71428 duk__emit_a_bc(comp_ctx,
71429 DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT,
71430 nargs /*num_args*/,
71431 reg_target /*target*/);
71432
71433 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
71434
71435 duk__ivalue_regconst(res, reg_target);
71436 return;
71437 }
71438
71439 /* FUNCTION EXPRESSIONS */
71440
71441 case DUK_TOK_FUNCTION: {
71442 /* Function expression. Note that any statement beginning with 'function'
71443 * is handled by the statement parser as a function declaration, or a
71444 * non-standard function expression/statement (or a SyntaxError). We only
71445 * handle actual function expressions (occurring inside an expression) here.
71446 *
71447 * O(depth^2) parse count for inner functions is handled by recording a
71448 * lexer offset on the first compilation pass, so that the function can
71449 * be efficiently skipped on the second pass. This is encapsulated into
71450 * duk__parse_func_like_fnum().
71451 */
71452
71453 duk_regconst_t reg_temp;
71454 duk_int_t fnum;
71455
71456 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71457
71458 /* curr_token follows 'function' */
71459 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/);
71460 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
71461
71462 duk__emit_a_bc(comp_ctx,
71463 DUK_OP_CLOSURE,
71464 reg_temp /*a*/,
71465 (duk_regconst_t) fnum /*bc*/);
71466
71467 duk__ivalue_regconst(res, reg_temp);
71468 return;
71469 }
71470
71471 /* UNARY EXPRESSIONS */
71472
71473 case DUK_TOK_DELETE: {
71474 /* Delete semantics are a bit tricky. The description in E5 specification
71475 * is kind of confusing, because it distinguishes between resolvability of
71476 * a reference (which is only known at runtime) seemingly at compile time
71477 * (= SyntaxError throwing).
71478 */
71479 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71480 if (res->t == DUK_IVAL_VAR) {
71481 /* not allowed in strict mode, regardless of whether resolves;
71482 * in non-strict mode DELVAR handles both non-resolving and
71483 * resolving cases (the specification description is a bit confusing).
71484 */
71485
71486 duk_regconst_t reg_temp;
71487 duk_regconst_t reg_varbind;
71488 duk_regconst_t rc_varname;
71489
71490 if (comp_ctx->curr_func.is_strict) {
71491 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
71492 DUK_WO_NORETURN(return;);
71493 }
71494
71495 DUK__SETTEMP(comp_ctx, temp_at_entry);
71496 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71497
71498 duk_dup(thr, res->x1.valstack_idx);
71499 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
71500 /* register bound variables are non-configurable -> always false */
71501 duk__emit_bc(comp_ctx,
71502 DUK_OP_LDFALSE,
71503 reg_temp);
71504 } else {
71505 duk_dup(thr, res->x1.valstack_idx);
71506 rc_varname = duk__getconst(comp_ctx);
71507 duk__emit_a_bc(comp_ctx,
71508 DUK_OP_DELVAR,
71509 reg_temp,
71510 rc_varname);
71511 }
71512 duk__ivalue_regconst(res, reg_temp);
71513 } else if (res->t == DUK_IVAL_PROP) {
71514 duk_regconst_t reg_temp;
71515 duk_regconst_t reg_obj;
71516 duk_regconst_t rc_key;
71517
71518 DUK__SETTEMP(comp_ctx, temp_at_entry);
71519 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71520 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
71521 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
71522 duk__emit_a_b_c(comp_ctx,
71523 DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST,
71524 reg_temp,
71525 reg_obj,
71526 rc_key);
71527
71528 duk__ivalue_regconst(res, reg_temp);
71529 } else {
71530 /* non-Reference deletion is always 'true', even in strict mode */
71531 duk_push_true(thr);
71532 goto plain_value;
71533 }
71534 return;
71535 }
71536 case DUK_TOK_VOID: {
71537 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71538 duk_push_undefined(thr);
71539 goto plain_value;
71540 }
71541 case DUK_TOK_TYPEOF: {
71542 /* 'typeof' must handle unresolvable references without throwing
71543 * a ReferenceError (E5 Section 11.4.3). Register mapped values
71544 * will never be unresolvable so special handling is only required
71545 * when an identifier is a "slow path" one.
71546 */
71547 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71548
71549 if (res->t == DUK_IVAL_VAR) {
71550 duk_regconst_t reg_varbind;
71551 duk_regconst_t rc_varname;
71552 duk_regconst_t reg_temp;
71553
71554 duk_dup(thr, res->x1.valstack_idx);
71555 if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
71556 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
71557 "at compile time, need to use special run-time handling"));
71558 reg_temp = DUK__ALLOCTEMP(comp_ctx);
71559 duk__emit_a_bc(comp_ctx,
71560 DUK_OP_TYPEOFID,
71561 reg_temp,
71562 rc_varname);
71563 duk__ivalue_regconst(res, reg_temp);
71564 return;
71565 }
71566 }
71567
71568 args = DUK_OP_TYPEOF;
71569 goto unary;
71570 }
71571 case DUK_TOK_INCREMENT: {
71572 args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR;
71573 goto preincdec;
71574 }
71575 case DUK_TOK_DECREMENT: {
71576 args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR;
71577 goto preincdec;
71578 }
71579 case DUK_TOK_ADD: {
71580 /* unary plus */
71581 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71582 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
71583 duk_is_number(thr, res->x1.valstack_idx)) {
71584 /* unary plus of a number is identity */
71585 return;
71586 }
71587 args = DUK_OP_UNP;
71588 goto unary;
71589 }
71590 case DUK_TOK_SUB: {
71591 /* unary minus */
71592 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71593 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
71594 duk_is_number(thr, res->x1.valstack_idx)) {
71595 /* this optimization is important to handle negative literals
71596 * (which are not directly provided by the lexical grammar)
71597 */
71598 duk_tval *tv_num;
71599 duk_double_union du;
71600
71601 tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
71602 DUK_ASSERT(tv_num != NULL);
71603 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
71604 du.d = DUK_TVAL_GET_NUMBER(tv_num);
71605 du.d = -du.d;
71606 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
71607 DUK_TVAL_SET_NUMBER(tv_num, du.d);
71608 return;
71609 }
71610 args = DUK_OP_UNM;
71611 goto unary;
71612 }
71613 case DUK_TOK_BNOT: {
71614 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71615 args = DUK_OP_BNOT;
71616 goto unary;
71617 }
71618 case DUK_TOK_LNOT: {
71619 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71620 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
71621 /* Very minimal inlining to handle common idioms '!0' and '!1',
71622 * and also boolean arguments like '!false' and '!true'.
71623 */
71624 duk_tval *tv_val;
71625
71626 tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
71627 DUK_ASSERT(tv_val != NULL);
71628 if (DUK_TVAL_IS_NUMBER(tv_val)) {
71629 duk_double_t d;
71630 d = DUK_TVAL_GET_NUMBER(tv_val);
71631 if (duk_double_equals(d, 0.0)) {
71632 /* Matches both +0 and -0 on purpose. */
71633 DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
71634 DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
71635 return;
71636 } else if (duk_double_equals(d, 1.0)) {
71637 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
71638 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
71639 return;
71640 }
71641 } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
71642 duk_small_uint_t v;
71643 v = DUK_TVAL_GET_BOOLEAN(tv_val);
71644 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
71645 DUK_ASSERT(v == 0 || v == 1);
71646 DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
71647 return;
71648 }
71649 }
71650 args = DUK_OP_LNOT;
71651 goto unary;
71652 }
71653
71654 } /* end switch */
71655
71656 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
71657 DUK_WO_NORETURN(return;);
71658
71659 unary:
71660 {
71661 /* Unary opcodes use just the 'BC' register source because it
71662 * matches current shuffle limits, and maps cleanly to 16 high
71663 * bits of the opcode.
71664 */
71665
71666 duk_regconst_t reg_src, reg_res;
71667
71668 reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/);
71669 if (DUK__ISREG_TEMP(comp_ctx, reg_src)) {
71670 reg_res = reg_src;
71671 } else {
71672 reg_res = DUK__ALLOCTEMP(comp_ctx);
71673 }
71674 duk__emit_a_bc(comp_ctx,
71675 args,
71676 reg_res,
71677 reg_src);
71678 duk__ivalue_regconst(res, reg_res);
71679 return;
71680 }
71681
71682 preincdec:
71683 {
71684 /* preincrement and predecrement */
71685 duk_regconst_t reg_res;
71686 duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */
71687 duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */
71688
71689 /* Specific assumptions for opcode numbering. */
71690 DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
71691 DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
71692
71693 reg_res = DUK__ALLOCTEMP(comp_ctx);
71694
71695 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
71696 if (res->t == DUK_IVAL_VAR) {
71697 duk_hstring *h_varname;
71698 duk_regconst_t reg_varbind;
71699 duk_regconst_t rc_varname;
71700
71701 h_varname = duk_known_hstring(thr, res->x1.valstack_idx);
71702
71703 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
71704 goto syntax_error;
71705 }
71706
71707 duk_dup(thr, res->x1.valstack_idx);
71708 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
71709 duk__emit_a_bc(comp_ctx,
71710 args_op1, /* e.g. DUK_OP_PREINCR */
71711 reg_res,
71712 reg_varbind);
71713 } else {
71714 duk__emit_a_bc(comp_ctx,
71715 args_op1 + 4, /* e.g. DUK_OP_PREINCV */
71716 reg_res,
71717 rc_varname);
71718 }
71719
71720 DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
71721 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
71722 } else if (res->t == DUK_IVAL_PROP) {
71723 duk_regconst_t reg_obj; /* allocate to reg only (not const) */
71724 duk_regconst_t rc_key;
71725 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
71726 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
71727 duk__emit_a_b_c(comp_ctx,
71728 args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */
71729 reg_res,
71730 reg_obj,
71731 rc_key);
71732 } else {
71733 /* Technically return value is not needed because INVLHS will
71734 * unconditially throw a ReferenceError. Coercion is necessary
71735 * for proper semantics (consider ToNumber() called for an object).
71736 * Use DUK_OP_UNP with a dummy register to get ToNumber().
71737 */
71738
71739 duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
71740 duk__emit_bc(comp_ctx,
71741 DUK_OP_UNP,
71742 reg_res); /* for side effects, result ignored */
71743 duk__emit_op_only(comp_ctx,
71744 DUK_OP_INVLHS);
71745 }
71746 DUK__SETTEMP(comp_ctx, reg_res + 1);
71747 duk__ivalue_regconst(res, reg_res);
71748 return;
71749 }
71750
71751 plain_value:
71752 {
71753 /* Stack top contains plain value */
71754 duk__ivalue_plain_fromstack(comp_ctx, res);
71755 return;
71756 }
71757
71758#if defined(DUK_USE_ES6)
71759 syntax_error_newtarget:
71760 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET);
71761 DUK_WO_NORETURN(return;);
71762#endif
71763
71764 syntax_error:
71765 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
71766 DUK_WO_NORETURN(return;);
71767}
71768
71769/* XXX: add flag to indicate whether caller cares about return value; this
71770 * affects e.g. handling of assignment expressions. This change needs API
71771 * changes elsewhere too.
71772 */
71773DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
71774 duk_hthread *thr = comp_ctx->thr;
71775 duk_token *tk;
71776 duk_small_uint_t tok;
71777 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
71778
71779 /*
71780 * ctx->prev_token token to process with duk__expr_led()
71781 * ctx->curr_token updated by caller
71782 */
71783
71784 comp_ctx->curr_func.led_count++;
71785
71786 /* The token in the switch has already been eaten here */
71787 tk = &comp_ctx->prev_token;
71788 tok = tk->t;
71789
71790 DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
71791 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
71792
71793 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
71794
71795 switch (tok) {
71796
71797 /* PRIMARY EXPRESSIONS */
71798
71799 case DUK_TOK_PERIOD: {
71800 /* Property access expressions are critical for correct LHS ordering,
71801 * see comments in duk__expr()!
71802 *
71803 * A conservative approach would be to use duk__ivalue_totempconst()
71804 * for 'left'. However, allowing a reg-bound variable seems safe here
71805 * and is nice because "foo.bar" is a common expression. If the ivalue
71806 * is used in an expression a GETPROP will occur before any changes to
71807 * the base value can occur. If the ivalue is used as an assignment
71808 * LHS, the assignment code will ensure the base value is safe from
71809 * RHS mutation.
71810 */
71811
71812 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
71813 * causes an extra LDREG in call setup. It's sufficient to coerce to a
71814 * unary ivalue?
71815 */
71816 duk__ivalue_toplain(comp_ctx, left);
71817
71818 /* NB: must accept reserved words as property name */
71819 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
71820 DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
71821 DUK_WO_NORETURN(return;);
71822 }
71823
71824 res->t = DUK_IVAL_PROP;
71825 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
71826 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
71827 duk_push_hstring(thr, comp_ctx->curr_token.str1);
71828 duk_replace(thr, res->x2.valstack_idx);
71829 res->x2.t = DUK_ISPEC_VALUE;
71830
71831 /* special RegExp literal handling after IdentifierName */
71832 comp_ctx->curr_func.reject_regexp_in_adv = 1;
71833
71834 duk__advance(comp_ctx);
71835 return;
71836 }
71837 case DUK_TOK_LBRACKET: {
71838 /* Property access expressions are critical for correct LHS ordering,
71839 * see comments in duk__expr()!
71840 */
71841
71842 /* XXX: optimize temp reg use */
71843 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
71844 /* XXX: coerce to regs? it might be better for enumeration use, where the
71845 * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
71846 * there?
71847 */
71848 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
71849 * emitted for the base value; could avoid it if we knew that
71850 * the key expression is safe (e.g. just a single literal).
71851 */
71852
71853 /* The 'left' value must not be a register bound variable
71854 * because it may be mutated during the rest of the expression
71855 * and E5.1 Section 11.2.1 specifies the order of evaluation
71856 * so that the base value is evaluated first.
71857 * See: test-bug-nested-prop-mutate.js.
71858 */
71859 duk__ivalue_totempconst(comp_ctx, left);
71860 duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
71861 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
71862
71863 res->t = DUK_IVAL_PROP;
71864 duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */
71865 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
71866 return;
71867 }
71868 case DUK_TOK_LPAREN: {
71869 /* function call */
71870 duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
71871 duk_int_t nargs;
71872 duk_small_uint_t call_op = DUK_OP_CALL0;
71873
71874 /* XXX: attempt to get the call result to "next temp" whenever
71875 * possible to avoid unnecessary register shuffles.
71876 */
71877
71878 /*
71879 * Setup call: target and 'this' binding. Three cases:
71880 *
71881 * 1. Identifier base (e.g. "foo()")
71882 * 2. Property base (e.g. "foo.bar()")
71883 * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
71884 */
71885
71886 if (left->t == DUK_IVAL_VAR) {
71887 duk_hstring *h_varname;
71888 duk_regconst_t reg_varbind;
71889 duk_regconst_t rc_varname;
71890
71891 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
71892
71893 h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
71894 if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
71895 /* Potential direct eval call detected, flag the CALL
71896 * so that a run-time "direct eval" check is made and
71897 * special behavior may be triggered. Note that this
71898 * does not prevent 'eval' from being register bound.
71899 */
71900 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
71901 "-> using EVALCALL, marking function "
71902 "as may_direct_eval"));
71903 call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL;
71904 comp_ctx->curr_func.may_direct_eval = 1;
71905 }
71906
71907 duk_dup(thr, left->x1.valstack_idx);
71908 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
71909 duk__emit_a_bc(comp_ctx,
71910 DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
71911 reg_varbind,
71912 reg_cs + 0);
71913 } else {
71914 /* XXX: expand target register or constant field to
71915 * reduce shuffling.
71916 */
71917 DUK_ASSERT(DUK__ISCONST(rc_varname));
71918 duk__emit_a_b(comp_ctx,
71919 DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST,
71920 reg_cs + 0,
71921 rc_varname);
71922 }
71923 } else if (left->t == DUK_IVAL_PROP) {
71924 /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i,
71925 * E5 Section 10.4.3. There used to be a separate CSPROP opcode
71926 * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST,
71927 * CSPROP) and the same can be achieved with ordinary loads.
71928 */
71929#if defined(DUK_USE_VERBOSE_ERRORS)
71930 duk_regconst_t reg_key;
71931#endif
71932
71933 DUK_DDD(DUK_DDDPRINT("function call with property base"));
71934
71935 /* XXX: For Math.sin() this generates: LDCONST + LDREG +
71936 * GETPROPC + call. The LDREG is unnecessary because LDCONST
71937 * could be loaded directly into reg_cs + 1. This doesn't
71938 * happen now because a variable cannot be in left->x1 of a
71939 * DUK_IVAL_PROP. We could notice that left->x1 is a temp
71940 * and reuse, but it would still be in the wrong position
71941 * (reg_cs + 0 rather than reg_cs + 1).
71942 */
71943 duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */
71944#if defined(DUK_USE_VERBOSE_ERRORS)
71945 reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
71946 duk__emit_a_b_c(comp_ctx,
71947 DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST,
71948 reg_cs + 0,
71949 reg_cs + 1,
71950 reg_key);
71951#else
71952 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */
71953#endif
71954 } else {
71955 DUK_DDD(DUK_DDDPRINT("function call with register base"));
71956
71957 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
71958#if 0
71959 duk__emit_a_bc(comp_ctx,
71960 DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
71961 reg_cs + 0,
71962 reg_cs + 0); /* in-place setup */
71963#endif
71964 /* Because of in-place setup, REGCS is equivalent to
71965 * just this LDUNDEF.
71966 */
71967 duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1);
71968 }
71969
71970 DUK__SETTEMP(comp_ctx, reg_cs + 2);
71971 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
71972
71973 /* Tailcalls are handled by back-patching the already emitted opcode
71974 * later in return statement parser.
71975 */
71976
71977 duk__emit_a_bc(comp_ctx,
71978 call_op,
71979 (duk_regconst_t) nargs /*numargs*/,
71980 reg_cs /*basereg*/);
71981 DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
71982
71983 duk__ivalue_regconst(res, reg_cs);
71984 return;
71985 }
71986
71987 /* POSTFIX EXPRESSION */
71988
71989 case DUK_TOK_INCREMENT: {
71990 args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0;
71991 goto postincdec;
71992 }
71993 case DUK_TOK_DECREMENT: {
71994 args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0;
71995 goto postincdec;
71996 }
71997
71998 /* EXPONENTIATION EXPRESSION */
71999
72000#if defined(DUK_USE_ES7_EXP_OPERATOR)
72001 case DUK_TOK_EXP: {
72002 args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1; /* UnaryExpression */
72003 goto binary;
72004 }
72005#endif
72006
72007 /* MULTIPLICATIVE EXPRESSION */
72008
72009 case DUK_TOK_MUL: {
72010 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
72011 goto binary;
72012 }
72013 case DUK_TOK_DIV: {
72014 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
72015 goto binary;
72016 }
72017 case DUK_TOK_MOD: {
72018 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
72019 goto binary;
72020 }
72021
72022 /* ADDITIVE EXPRESSION */
72023
72024 case DUK_TOK_ADD: {
72025 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
72026 goto binary;
72027 }
72028 case DUK_TOK_SUB: {
72029 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
72030 goto binary;
72031 }
72032
72033 /* SHIFT EXPRESSION */
72034
72035 case DUK_TOK_ALSHIFT: {
72036 /* << */
72037 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
72038 goto binary;
72039 }
72040 case DUK_TOK_ARSHIFT: {
72041 /* >> */
72042 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
72043 goto binary;
72044 }
72045 case DUK_TOK_RSHIFT: {
72046 /* >>> */
72047 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
72048 goto binary;
72049 }
72050
72051 /* RELATIONAL EXPRESSION */
72052
72053 case DUK_TOK_LT: {
72054 /* < */
72055 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
72056 goto binary;
72057 }
72058 case DUK_TOK_GT: {
72059 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
72060 goto binary;
72061 }
72062 case DUK_TOK_LE: {
72063 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
72064 goto binary;
72065 }
72066 case DUK_TOK_GE: {
72067 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
72068 goto binary;
72069 }
72070 case DUK_TOK_INSTANCEOF: {
72071 args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL;
72072 goto binary;
72073 }
72074 case DUK_TOK_IN: {
72075 args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL;
72076 goto binary;
72077 }
72078
72079 /* EQUALITY EXPRESSION */
72080
72081 case DUK_TOK_EQ: {
72082 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
72083 goto binary;
72084 }
72085 case DUK_TOK_NEQ: {
72086 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
72087 goto binary;
72088 }
72089 case DUK_TOK_SEQ: {
72090 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
72091 goto binary;
72092 }
72093 case DUK_TOK_SNEQ: {
72094 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
72095 goto binary;
72096 }
72097
72098 /* BITWISE EXPRESSIONS */
72099
72100 case DUK_TOK_BAND: {
72101 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
72102 goto binary;
72103 }
72104 case DUK_TOK_BXOR: {
72105 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
72106 goto binary;
72107 }
72108 case DUK_TOK_BOR: {
72109 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
72110 goto binary;
72111 }
72112
72113 /* LOGICAL EXPRESSIONS */
72114
72115 case DUK_TOK_LAND: {
72116 /* syntactically left-associative but parsed as right-associative */
72117 args = (1 << 8) + DUK__BP_LAND - 1;
72118 goto binary_logical;
72119 }
72120 case DUK_TOK_LOR: {
72121 /* syntactically left-associative but parsed as right-associative */
72122 args = (0 << 8) + DUK__BP_LOR - 1;
72123 goto binary_logical;
72124 }
72125
72126 /* CONDITIONAL EXPRESSION */
72127
72128 case DUK_TOK_QUESTION: {
72129 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
72130 * but only if it really is a temp. Nothing fancy here now.
72131 */
72132 duk_regconst_t reg_temp;
72133 duk_int_t pc_jump1;
72134 duk_int_t pc_jump2;
72135
72136 reg_temp = DUK__ALLOCTEMP(comp_ctx);
72137 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
72138 duk__emit_if_true_skip(comp_ctx, reg_temp);
72139 pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */
72140 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
72141 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
72142 pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */
72143 duk__patch_jump_here(comp_ctx, pc_jump1);
72144 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
72145 duk__patch_jump_here(comp_ctx, pc_jump2);
72146
72147 DUK__SETTEMP(comp_ctx, reg_temp + 1);
72148 duk__ivalue_regconst(res, reg_temp);
72149 return;
72150 }
72151
72152 /* ASSIGNMENT EXPRESSION */
72153
72154 case DUK_TOK_EQUALSIGN: {
72155 /*
72156 * Assignments are right associative, allows e.g.
72157 * a = 5;
72158 * a += b = 9; // same as a += (b = 9)
72159 * -> expression value 14, a = 14, b = 9
72160 *
72161 * Right associativiness is reflected in the BP for recursion,
72162 * "-1" ensures assignment operations are allowed.
72163 *
72164 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
72165 */
72166 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
72167 goto assign;
72168 }
72169 case DUK_TOK_ADD_EQ: {
72170 /* right associative */
72171 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
72172 goto assign;
72173 }
72174 case DUK_TOK_SUB_EQ: {
72175 /* right associative */
72176 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
72177 goto assign;
72178 }
72179 case DUK_TOK_MUL_EQ: {
72180 /* right associative */
72181 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
72182 goto assign;
72183 }
72184 case DUK_TOK_DIV_EQ: {
72185 /* right associative */
72186 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
72187 goto assign;
72188 }
72189 case DUK_TOK_MOD_EQ: {
72190 /* right associative */
72191 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
72192 goto assign;
72193 }
72194#if defined(DUK_USE_ES7_EXP_OPERATOR)
72195 case DUK_TOK_EXP_EQ: {
72196 /* right associative */
72197 args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1;
72198 goto assign;
72199 }
72200#endif
72201 case DUK_TOK_ALSHIFT_EQ: {
72202 /* right associative */
72203 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
72204 goto assign;
72205 }
72206 case DUK_TOK_ARSHIFT_EQ: {
72207 /* right associative */
72208 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
72209 goto assign;
72210 }
72211 case DUK_TOK_RSHIFT_EQ: {
72212 /* right associative */
72213 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
72214 goto assign;
72215 }
72216 case DUK_TOK_BAND_EQ: {
72217 /* right associative */
72218 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
72219 goto assign;
72220 }
72221 case DUK_TOK_BOR_EQ: {
72222 /* right associative */
72223 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
72224 goto assign;
72225 }
72226 case DUK_TOK_BXOR_EQ: {
72227 /* right associative */
72228 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
72229 goto assign;
72230 }
72231
72232 /* COMMA */
72233
72234 case DUK_TOK_COMMA: {
72235 /* right associative */
72236
72237 duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */
72238 duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
72239
72240 /* return 'res' (of right part) as our result */
72241 return;
72242 }
72243
72244 default: {
72245 break;
72246 }
72247 }
72248
72249 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
72250 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
72251 DUK_WO_NORETURN(return;);
72252
72253#if 0
72254 /* XXX: shared handling for 'duk__expr_lhs'? */
72255 if (comp_ctx->curr_func.paren_level == 0 && XXX) {
72256 comp_ctx->curr_func.duk__expr_lhs = 0;
72257 }
72258#endif
72259
72260 binary:
72261 /*
72262 * Shared handling of binary operations
72263 *
72264 * args = (opcode << 8) + rbp
72265 */
72266 {
72267 duk__ivalue_toplain(comp_ctx, left);
72268 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
72269
72270 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
72271 DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
72272 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
72273
72274 res->t = DUK_IVAL_ARITH;
72275 res->op = (args >> 8) & 0xff;
72276
72277 res->x2.t = res->x1.t;
72278 res->x2.regconst = res->x1.regconst;
72279 duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx);
72280
72281 res->x1.t = left->x1.t;
72282 res->x1.regconst = left->x1.regconst;
72283 duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx);
72284
72285 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
72286 (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
72287 return;
72288 }
72289
72290 binary_logical:
72291 /*
72292 * Shared handling for logical AND and logical OR.
72293 *
72294 * args = (truthval << 8) + rbp
72295 *
72296 * Truthval determines when to skip right-hand-side.
72297 * For logical AND truthval=1, for logical OR truthval=0.
72298 *
72299 * See doc/compiler.rst for discussion on compiling logical
72300 * AND and OR expressions. The approach here is very simplistic,
72301 * generating extra jumps and multiple evaluations of truth values,
72302 * but generates code on-the-fly with only local back-patching.
72303 *
72304 * Both logical AND and OR are syntactically left-associated.
72305 * However, logical ANDs are compiled as right associative
72306 * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
72307 * skip jumps to skip over the entire tail. Similarly for logical OR.
72308 */
72309
72310 {
72311 duk_regconst_t reg_temp;
72312 duk_int_t pc_jump;
72313 duk_small_uint_t args_truthval = args >> 8;
72314 duk_small_uint_t args_rbp = args & 0xff;
72315
72316 /* XXX: unoptimal use of temps, resetting */
72317
72318 reg_temp = DUK__ALLOCTEMP(comp_ctx);
72319
72320 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
72321 DUK_ASSERT(DUK__ISREG(reg_temp));
72322 duk__emit_bc(comp_ctx,
72323 (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
72324 reg_temp); /* skip jump conditionally */
72325 pc_jump = duk__emit_jump_empty(comp_ctx);
72326 duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
72327 duk__patch_jump_here(comp_ctx, pc_jump);
72328
72329 duk__ivalue_regconst(res, reg_temp);
72330 return;
72331 }
72332
72333 assign:
72334 /*
72335 * Shared assignment expression handling
72336 *
72337 * args = (opcode << 8) + rbp
72338 *
72339 * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
72340 * Syntactically valid left-hand-side forms which are not accepted as
72341 * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
72342 * SyntaxError, but rather a run-time ReferenceError.
72343 *
72344 * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
72345 * to a temporary first. The RHS is then evaluated. Finally, the
72346 * <op> is applied to the initial value of RHS (not the value after
72347 * RHS evaluation), and written to X. Doing so concretely generates
72348 * inefficient code so we'd like to avoid the temporary when possible.
72349 * See: https://github.com/svaarala/duktape/pull/992.
72350 *
72351 * The expression value (final LHS value, written to RHS) is
72352 * conceptually copied into a fresh temporary so that it won't
72353 * change even if the LHS/RHS values change in outer expressions.
72354 * For example, it'd be generally incorrect for the expression value
72355 * to be the RHS register binding, unless there's a guarantee that it
72356 * won't change during further expression evaluation. Using the
72357 * temporary concretely produces inefficient bytecode, so we try to
72358 * avoid the extra temporary for some known-to-be-safe cases.
72359 * Currently the only safe case we detect is a "top level assignment",
72360 * for example "x = y + z;", where the assignment expression value is
72361 * ignored.
72362 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
72363 */
72364
72365 {
72366 duk_small_uint_t args_op = args >> 8;
72367 duk_small_uint_t args_rbp = args & 0xff;
72368 duk_bool_t toplevel_assign;
72369
72370 /* XXX: here we need to know if 'left' is left-hand-side compatible.
72371 * That information is no longer available from current expr parsing
72372 * state; it would need to be carried into the 'left' ivalue or by
72373 * some other means.
72374 */
72375
72376 /* A top-level assignment is e.g. "x = y;". For these it's safe
72377 * to use the RHS as-is as the expression value, even if the RHS
72378 * is a reg-bound identifier. The RHS ('res') is right associative
72379 * so it has consumed all other assignment level operations; the
72380 * only relevant lower binding power construct is comma operator
72381 * which will ignore the expression value provided here. Usually
72382 * the top level assignment expression value is ignored, but it
72383 * is relevant for e.g. eval code.
72384 */
72385 toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
72386 comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
72387 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
72388 (long) comp_ctx->curr_func.nud_count,
72389 (long) comp_ctx->curr_func.led_count,
72390 (long) toplevel_assign));
72391
72392 if (left->t == DUK_IVAL_VAR) {
72393 duk_hstring *h_varname;
72394 duk_regconst_t reg_varbind;
72395 duk_regconst_t rc_varname;
72396
72397 DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
72398
72399 h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
72400 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
72401 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
72402 goto syntax_error_lvalue;
72403 }
72404 duk_dup(thr, left->x1.valstack_idx);
72405 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
72406
72407 if (args_op == DUK_OP_NONE) {
72408 duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
72409 if (toplevel_assign) {
72410 /* Any 'res' will do. */
72411 DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
72412 } else {
72413 /* 'res' must be a plain ivalue, and not register-bound variable. */
72414 DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
72415 if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
72416 DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) {
72417 duk__ivalue_totempconst(comp_ctx, res);
72418 }
72419 }
72420 } else {
72421 /* For X <op>= Y we need to evaluate the pre-op
72422 * value of X before evaluating the RHS: the RHS
72423 * can change X, but when we do <op> we must use
72424 * the pre-op value.
72425 */
72426 duk_regconst_t reg_temp;
72427
72428 reg_temp = DUK__ALLOCTEMP(comp_ctx);
72429
72430 if (reg_varbind >= 0) {
72431 duk_regconst_t reg_res;
72432 duk_regconst_t reg_src;
72433 duk_int_t pc_temp_load;
72434 duk_int_t pc_before_rhs;
72435 duk_int_t pc_after_rhs;
72436
72437 if (toplevel_assign) {
72438 /* 'reg_varbind' is the operation result and can also
72439 * become the expression value for top level assignments
72440 * such as: "var x; x += y;".
72441 */
72442 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
72443 reg_res = reg_varbind;
72444 } else {
72445 /* Not safe to use 'reg_varbind' as assignment expression
72446 * value, so go through a temp.
72447 */
72448 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
72449 reg_res = reg_temp; /* reg_res should be smallest possible */
72450 reg_temp = DUK__ALLOCTEMP(comp_ctx);
72451 }
72452
72453 /* Try to optimize X <op>= Y for reg-bound
72454 * variables. Detect side-effect free RHS
72455 * narrowly by seeing whether it emits code.
72456 * If not, rewind the code emitter and overwrite
72457 * the unnecessary temp reg load.
72458 */
72459
72460 pc_temp_load = duk__get_current_pc(comp_ctx);
72461 duk__emit_a_bc(comp_ctx,
72462 DUK_OP_LDREG,
72463 reg_temp,
72464 reg_varbind);
72465
72466 pc_before_rhs = duk__get_current_pc(comp_ctx);
72467 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
72468 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
72469 pc_after_rhs = duk__get_current_pc(comp_ctx);
72470
72471 DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
72472 (long) pc_temp_load, (long) pc_before_rhs,
72473 (long) pc_after_rhs));
72474
72475 if (pc_after_rhs == pc_before_rhs) {
72476 /* Note: if the reg_temp load generated shuffling
72477 * instructions, we may need to rewind more than
72478 * one instruction, so use explicit PC computation.
72479 */
72480 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
72481 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * (duk_int_t) sizeof(duk_compiler_instr));
72482 reg_src = reg_varbind;
72483 } else {
72484 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
72485 reg_src = reg_temp;
72486 }
72487
72488 duk__emit_a_b_c(comp_ctx,
72489 args_op | DUK__EMIT_FLAG_BC_REGCONST,
72490 reg_res,
72491 reg_src,
72492 res->x1.regconst);
72493
72494 res->x1.regconst = reg_res;
72495
72496 /* Ensure compact use of temps. */
72497 if (DUK__ISREG_TEMP(comp_ctx, reg_res)) {
72498 DUK__SETTEMP(comp_ctx, reg_res + 1);
72499 }
72500 } else {
72501 /* When LHS is not register bound, always go through a
72502 * temporary. No optimization for top level assignment.
72503 */
72504
72505 duk__emit_a_bc(comp_ctx,
72506 DUK_OP_GETVAR,
72507 reg_temp,
72508 rc_varname);
72509
72510 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
72511 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
72512
72513 duk__emit_a_b_c(comp_ctx,
72514 args_op | DUK__EMIT_FLAG_BC_REGCONST,
72515 reg_temp,
72516 reg_temp,
72517 res->x1.regconst);
72518 res->x1.regconst = reg_temp;
72519 }
72520
72521 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
72522 }
72523
72524 /* At this point 'res' holds the potential expression value.
72525 * It can be basically any ivalue here, including a reg-bound
72526 * identifier (if code above deems it safe) or a unary/binary
72527 * operation. Operations must be resolved to a side effect free
72528 * plain value, and the side effects must happen exactly once.
72529 */
72530
72531 if (reg_varbind >= 0) {
72532 if (res->t != DUK_IVAL_PLAIN) {
72533 /* Resolve 'res' directly into the LHS binding, and use
72534 * that as the expression value if safe. If not safe,
72535 * resolve to a temp/const and copy to LHS.
72536 */
72537 if (toplevel_assign) {
72538 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
72539 } else {
72540 duk__ivalue_totempconst(comp_ctx, res);
72541 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
72542 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
72543 }
72544 } else {
72545 /* Use 'res' as the expression value (it's side effect
72546 * free and may be a plain value, a register, or a
72547 * constant) and write it to the LHS binding too.
72548 */
72549 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
72550 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
72551 }
72552 } else {
72553 /* Only a reg fits into 'A' so coerce 'res' into a register
72554 * for PUTVAR.
72555 *
72556 * XXX: here the current A/B/C split is suboptimal: we could
72557 * just use 9 bits for reg_res (and support constants) and 17
72558 * instead of 18 bits for the varname const index.
72559 */
72560
72561 duk__ivalue_toreg(comp_ctx, res);
72562 duk__emit_a_bc(comp_ctx,
72563 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
72564 res->x1.regconst,
72565 rc_varname);
72566 }
72567
72568 /* 'res' contains expression value */
72569 } else if (left->t == DUK_IVAL_PROP) {
72570 /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
72571 duk_regconst_t reg_obj;
72572 duk_regconst_t rc_key;
72573 duk_regconst_t rc_res;
72574 duk_regconst_t reg_temp;
72575
72576 /* Property access expressions ('a[b]') are critical to correct
72577 * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
72578 * We must make sure that the LHS target slot (base object and
72579 * key) don't change during RHS evaluation. The only concrete
72580 * problem is a register reference to a variable-bound register
72581 * (i.e., non-temp). Require temp regs for both key and base.
72582 *
72583 * Don't allow a constant for the object (even for a number
72584 * etc), as it goes into the 'A' field of the opcode.
72585 */
72586
72587 reg_obj = duk__ispec_toregconst_raw(comp_ctx,
72588 &left->x1,
72589 -1 /*forced_reg*/,
72590 DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
72591
72592 rc_key = duk__ispec_toregconst_raw(comp_ctx,
72593 &left->x2,
72594 -1 /*forced_reg*/,
72595 DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
72596
72597 /* Evaluate RHS only when LHS is safe. */
72598
72599 if (args_op == DUK_OP_NONE) {
72600 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
72601 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
72602 rc_res = res->x1.regconst;
72603 } else {
72604 reg_temp = DUK__ALLOCTEMP(comp_ctx);
72605 duk__emit_a_b_c(comp_ctx,
72606 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
72607 reg_temp,
72608 reg_obj,
72609 rc_key);
72610
72611 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
72612 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
72613
72614 duk__emit_a_b_c(comp_ctx,
72615 args_op | DUK__EMIT_FLAG_BC_REGCONST,
72616 reg_temp,
72617 reg_temp,
72618 res->x1.regconst);
72619 rc_res = reg_temp;
72620 }
72621
72622 duk__emit_a_b_c(comp_ctx,
72623 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
72624 reg_obj,
72625 rc_key,
72626 rc_res);
72627
72628 duk__ivalue_regconst(res, rc_res);
72629 } else {
72630 /* No support for lvalues returned from new or function call expressions.
72631 * However, these must NOT cause compile-time SyntaxErrors, but run-time
72632 * ReferenceErrors. Both left and right sides of the assignment must be
72633 * evaluated before throwing a ReferenceError. For instance:
72634 *
72635 * f() = g();
72636 *
72637 * must result in f() being evaluated, then g() being evaluated, and
72638 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
72639 */
72640
72641 duk_regconst_t rc_res;
72642
72643 /* First evaluate LHS fully to ensure all side effects are out. */
72644 duk__ivalue_toplain_ignore(comp_ctx, left);
72645
72646 /* Then evaluate RHS fully (its value becomes the expression value too).
72647 * Technically we'd need the side effect safety check here too, but because
72648 * we always throw using INVLHS the result doesn't matter.
72649 */
72650 rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
72651
72652 duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
72653
72654 duk__ivalue_regconst(res, rc_res);
72655 }
72656
72657 return;
72658 }
72659
72660 postincdec:
72661 {
72662 /*
72663 * Post-increment/decrement will return the original value as its
72664 * result value. However, even that value will be coerced using
72665 * ToNumber() which is quite awkward. Specific bytecode opcodes
72666 * are used to handle these semantics.
72667 *
72668 * Note that post increment/decrement has a "no LineTerminator here"
72669 * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
72670 * the previous expression if a LineTerminator occurs before '++'/'--'.
72671 */
72672
72673 duk_regconst_t reg_res;
72674 duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */
72675 duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */
72676
72677 /* Specific assumptions for opcode numbering. */
72678 DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
72679 DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
72680
72681 reg_res = DUK__ALLOCTEMP(comp_ctx);
72682
72683 if (left->t == DUK_IVAL_VAR) {
72684 duk_hstring *h_varname;
72685 duk_regconst_t reg_varbind;
72686 duk_regconst_t rc_varname;
72687
72688 h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
72689
72690 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
72691 goto syntax_error;
72692 }
72693
72694 duk_dup(thr, left->x1.valstack_idx);
72695 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
72696 duk__emit_a_bc(comp_ctx,
72697 args_op1, /* e.g. DUK_OP_POSTINCR */
72698 reg_res,
72699 reg_varbind);
72700 } else {
72701 duk__emit_a_bc(comp_ctx,
72702 args_op1 + 4, /* e.g. DUK_OP_POSTINCV */
72703 reg_res,
72704 rc_varname);
72705 }
72706
72707 DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
72708 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
72709 } else if (left->t == DUK_IVAL_PROP) {
72710 duk_regconst_t reg_obj; /* allocate to reg only (not const) */
72711 duk_regconst_t rc_key;
72712
72713 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
72714 rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
72715 duk__emit_a_b_c(comp_ctx,
72716 args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */
72717 reg_res,
72718 reg_obj,
72719 rc_key);
72720 } else {
72721 /* Technically return value is not needed because INVLHS will
72722 * unconditially throw a ReferenceError. Coercion is necessary
72723 * for proper semantics (consider ToNumber() called for an object).
72724 * Use DUK_OP_UNP with a dummy register to get ToNumber().
72725 */
72726 duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
72727 duk__emit_bc(comp_ctx,
72728 DUK_OP_UNP,
72729 reg_res); /* for side effects, result ignored */
72730 duk__emit_op_only(comp_ctx,
72731 DUK_OP_INVLHS);
72732 }
72733
72734 DUK__SETTEMP(comp_ctx, reg_res + 1);
72735 duk__ivalue_regconst(res, reg_res);
72736 return;
72737 }
72738
72739 syntax_error:
72740 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
72741 DUK_WO_NORETURN(return;);
72742
72743 syntax_error_lvalue:
72744 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
72745 DUK_WO_NORETURN(return;);
72746}
72747
72748DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
72749 duk_small_uint_t tok = comp_ctx->curr_token.t;
72750
72751 DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL); /* unsigned */
72752 DUK_ASSERT(tok <= DUK_TOK_MAXVAL);
72753 DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
72754
72755 /* XXX: integrate support for this into led() instead?
72756 * Similar issue as post-increment/post-decrement.
72757 */
72758
72759 /* prevent duk__expr_led() by using a binding power less than anything valid */
72760 if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
72761 return 0;
72762 }
72763
72764 if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
72765 (comp_ctx->curr_token.lineterm)) {
72766 /* '++' or '--' in a post-increment/decrement position,
72767 * and a LineTerminator occurs between the operator and
72768 * the preceding expression. Force the previous expr
72769 * to terminate, in effect treating e.g. "a,b\n++" as
72770 * "a,b;++" (= SyntaxError).
72771 */
72772 return 0;
72773 }
72774
72775 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
72776}
72777
72778/*
72779 * Expression parsing.
72780 *
72781 * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
72782 * first token of the expression. Upon exit, 'curr_tok' will be the first
72783 * token not part of the expression (e.g. semicolon terminating an expression
72784 * statement).
72785 */
72786
72787#define DUK__EXPR_RBP_MASK 0xff
72788#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
72789#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
72790#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
72791
72792/* main expression parser function */
72793DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72794 duk_hthread *thr = comp_ctx->thr;
72795 duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
72796 duk_ivalue *tmp = &tmp_alloc;
72797 duk_small_uint_t rbp;
72798
72799 DUK__RECURSION_INCREASE(comp_ctx, thr);
72800
72801 duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS);
72802
72803 /* filter out flags from exprtop rbp_flags here to save space */
72804 rbp = rbp_flags & DUK__EXPR_RBP_MASK;
72805
72806 DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
72807 (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
72808 (long) comp_ctx->curr_func.paren_level));
72809
72810 duk_memzero(&tmp_alloc, sizeof(tmp_alloc));
72811 tmp->x1.valstack_idx = duk_get_top(thr);
72812 tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
72813 duk_push_undefined(thr);
72814 duk_push_undefined(thr);
72815
72816 /* XXX: where to release temp regs in intermediate expressions?
72817 * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
72818 * that particular expression temp regs can be forced here.
72819 */
72820
72821 /* XXX: increase ctx->expr_tokens here for every consumed token
72822 * (this would be a nice statistic)?
72823 */
72824
72825 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
72826 /* XXX: possibly incorrect handling of empty expression */
72827 DUK_DDD(DUK_DDDPRINT("empty expression"));
72828 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
72829 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
72830 DUK_WO_NORETURN(return;);
72831 }
72832 duk_push_undefined(thr);
72833 duk__ivalue_plain_fromstack(comp_ctx, res);
72834 goto cleanup;
72835 }
72836
72837 duk__advance(comp_ctx);
72838 duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */
72839 while (rbp < duk__expr_lbp(comp_ctx)) {
72840 duk__advance(comp_ctx);
72841 duk__expr_led(comp_ctx, res, tmp);
72842 duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */
72843 }
72844
72845 cleanup:
72846 /* final result is already in 'res' */
72847
72848 duk_pop_2(thr);
72849
72850 DUK__RECURSION_DECREASE(comp_ctx, thr);
72851}
72852
72853DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72854 duk_hthread *thr = comp_ctx->thr;
72855
72856 /* Note: these variables must reside in 'curr_func' instead of the global
72857 * context: when parsing function expressions, expression parsing is nested.
72858 */
72859 comp_ctx->curr_func.nud_count = 0;
72860 comp_ctx->curr_func.led_count = 0;
72861 comp_ctx->curr_func.paren_level = 0;
72862 comp_ctx->curr_func.expr_lhs = 1;
72863 comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
72864
72865 duk__expr(comp_ctx, res, rbp_flags);
72866
72867 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
72868 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
72869 DUK_WO_NORETURN(return;);
72870 }
72871}
72872
72873/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
72874 * and result conversions.
72875 *
72876 * Each helper needs at least 2-3 calls to make it worth while to wrap.
72877 */
72878
72879#if 0 /* unused */
72880DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72881 duk__expr(comp_ctx, res, rbp_flags);
72882 return duk__ivalue_toreg(comp_ctx, res);
72883}
72884#endif
72885
72886#if 0 /* unused */
72887DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72888 duk__expr(comp_ctx, res, rbp_flags);
72889 return duk__ivalue_totemp(comp_ctx, res);
72890}
72891#endif
72892
72893DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
72894 DUK_ASSERT(forced_reg >= 0);
72895 duk__expr(comp_ctx, res, rbp_flags);
72896 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
72897}
72898
72899DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72900 duk__expr(comp_ctx, res, rbp_flags);
72901 return duk__ivalue_toregconst(comp_ctx, res);
72902}
72903
72904#if 0 /* unused */
72905DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72906 duk__expr(comp_ctx, res, rbp_flags);
72907 return duk__ivalue_totempconst(comp_ctx, res);
72908}
72909#endif
72910
72911DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72912 duk__expr(comp_ctx, res, rbp_flags);
72913 duk__ivalue_toplain(comp_ctx, res);
72914}
72915
72916DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72917 duk__expr(comp_ctx, res, rbp_flags);
72918 duk__ivalue_toplain_ignore(comp_ctx, res);
72919}
72920
72921DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72922 duk__exprtop(comp_ctx, res, rbp_flags);
72923 return duk__ivalue_toreg(comp_ctx, res);
72924}
72925
72926#if 0 /* unused */
72927DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72928 duk__exprtop(comp_ctx, res, rbp_flags);
72929 return duk__ivalue_totemp(comp_ctx, res);
72930}
72931#endif
72932
72933DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
72934 DUK_ASSERT(forced_reg >= 0);
72935 duk__exprtop(comp_ctx, res, rbp_flags);
72936 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
72937}
72938
72939DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
72940 duk__exprtop(comp_ctx, res, rbp_flags);
72941 return duk__ivalue_toregconst(comp_ctx, res);
72942}
72943
72944#if 0 /* unused */
72945DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
72946 duk__exprtop(comp_ctx, res, rbp_flags);
72947 duk__ivalue_toplain_ignore(comp_ctx, res);
72948}
72949#endif
72950
72951/*
72952 * Parse an individual source element (top level statement) or a statement.
72953 *
72954 * Handles labeled statements automatically (peeling away labels before
72955 * parsing an expression that follows the label(s)).
72956 *
72957 * Upon entry, 'curr_tok' contains the first token of the statement (parsed
72958 * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
72959 * token following the statement (if the statement has a terminator, this is
72960 * the token after the terminator).
72961 */
72962
72963#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
72964#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
72965#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
72966#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
72967#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
72968
72969/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
72970 * has already been eaten. These is no return value in 'res', it is used only
72971 * as a temporary.
72972 *
72973 * When called from 'for-in' statement parser, the initializer expression must
72974 * not allow the 'in' token. The caller supply additional expression parsing
72975 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
72976 *
72977 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
72978 * the identifier is bound:
72979 *
72980 * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
72981 * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
72982 *
72983 * These allow the caller to use the variable for further assignment, e.g.
72984 * as is done in 'for-in' parsing.
72985 */
72986
72987DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
72988 duk_hthread *thr = comp_ctx->thr;
72989 duk_hstring *h_varname;
72990 duk_regconst_t reg_varbind;
72991 duk_regconst_t rc_varname;
72992
72993 /* assume 'var' has been eaten */
72994
72995 /* Note: Identifier rejects reserved words */
72996 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
72997 goto syntax_error;
72998 }
72999 h_varname = comp_ctx->curr_token.str1;
73000
73001 DUK_ASSERT(h_varname != NULL);
73002
73003 /* strict mode restrictions (E5 Section 12.2.1) */
73004 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
73005 goto syntax_error;
73006 }
73007
73008 /* register declarations in first pass */
73009 if (comp_ctx->curr_func.in_scanning) {
73010 duk_uarridx_t n;
73011 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
73012 (duk_heaphdr *) h_varname));
73013 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
73014 duk_push_hstring(thr, h_varname);
73015 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
73016 duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8));
73017 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
73018 }
73019
73020 duk_push_hstring(thr, h_varname); /* push before advancing to keep reachable */
73021
73022 /* register binding lookup is based on varmap (even in first pass) */
73023 duk_dup_top(thr);
73024 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
73025
73026 duk__advance(comp_ctx); /* eat identifier */
73027
73028 if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
73029 duk__advance(comp_ctx);
73030
73031 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
73032 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
73033
73034 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
73035
73036 if (reg_varbind >= 0) {
73037 duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
73038 } else {
73039 duk_regconst_t reg_val;
73040 reg_val = duk__ivalue_toreg(comp_ctx, res);
73041 duk__emit_a_bc(comp_ctx,
73042 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
73043 reg_val,
73044 rc_varname);
73045 }
73046 } else {
73047 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
73048 /* Used for minimal 'const': initializer required. */
73049 goto syntax_error;
73050 }
73051 }
73052
73053 duk_pop(thr); /* pop varname */
73054
73055 *out_rc_varname = rc_varname;
73056 *out_reg_varbind = reg_varbind;
73057
73058 return;
73059
73060 syntax_error:
73061 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
73062 DUK_WO_NORETURN(return;);
73063}
73064
73065DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
73066 duk_regconst_t reg_varbind;
73067 duk_regconst_t rc_varname;
73068
73069 duk__advance(comp_ctx); /* eat 'var' */
73070
73071 for (;;) {
73072 /* rc_varname and reg_varbind are ignored here */
73073 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
73074
73075 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
73076 break;
73077 }
73078 duk__advance(comp_ctx);
73079 }
73080}
73081
73082DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
73083 duk_hthread *thr = comp_ctx->thr;
73084 duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
73085 duk_regconst_t temp_reset; /* knock back "next temp" to this whenever possible */
73086 duk_regconst_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
73087
73088 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
73089
73090 /* Two temporaries are preallocated here for variants 3 and 4 which need
73091 * registers which are never clobbered by expressions in the loop
73092 * (concretely: for the enumerator object and the next enumerated value).
73093 * Variants 1 and 2 "release" these temps.
73094 */
73095
73096 reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
73097
73098 temp_reset = DUK__GETTEMP(comp_ctx);
73099
73100 /*
73101 * For/for-in main variants are:
73102 *
73103 * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
73104 * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
73105 * 3. for (LeftHandSideExpression in Expression) Statement
73106 * 4. for (var VariableDeclarationNoIn in Expression) Statement
73107 *
73108 * Parsing these without arbitrary lookahead or backtracking is relatively
73109 * tricky but we manage to do so for now.
73110 *
73111 * See doc/compiler.rst for a detailed discussion of control flow
73112 * issues, evaluation order issues, etc.
73113 */
73114
73115 duk__advance(comp_ctx); /* eat 'for' */
73116 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
73117
73118 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
73119
73120 /* a label site has been emitted by duk__parse_stmt() automatically
73121 * (it will also emit the ENDLABEL).
73122 */
73123
73124 if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
73125 /*
73126 * Variant 2 or 4
73127 */
73128
73129 duk_regconst_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
73130 duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
73131
73132 duk__advance(comp_ctx); /* eat 'var' */
73133 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
73134 DUK__SETTEMP(comp_ctx, temp_reset);
73135
73136 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
73137 /*
73138 * Variant 4
73139 */
73140
73141 DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
73142 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */
73143 if (reg_varbind >= 0) {
73144 duk__emit_a_bc(comp_ctx,
73145 DUK_OP_LDREG,
73146 reg_varbind,
73147 reg_temps + 0);
73148 } else {
73149 duk__emit_a_bc(comp_ctx,
73150 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
73151 reg_temps + 0,
73152 rc_varname);
73153 }
73154 goto parse_3_or_4;
73155 } else {
73156 /*
73157 * Variant 2
73158 */
73159
73160 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
73161 for (;;) {
73162 /* more initializers */
73163 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
73164 break;
73165 }
73166 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
73167
73168 duk__advance(comp_ctx); /* eat comma */
73169 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
73170 }
73171 goto parse_1_or_2;
73172 }
73173 } else {
73174 /*
73175 * Variant 1 or 3
73176 */
73177
73178 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
73179
73180 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
73181 * so any loop variables (e.g. enumerator) must be "preallocated".
73182 */
73183
73184 /* don't coerce yet to a plain value (variant 3 needs special handling) */
73185 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */
73186 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
73187 /*
73188 * Variant 3
73189 */
73190
73191 /* XXX: need to determine LHS type, and check that it is LHS compatible */
73192 DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
73193 if (duk__expr_is_empty(comp_ctx)) {
73194 goto syntax_error; /* LeftHandSideExpression does not allow empty expression */
73195 }
73196
73197 if (res->t == DUK_IVAL_VAR) {
73198 duk_regconst_t reg_varbind;
73199 duk_regconst_t rc_varname;
73200
73201 duk_dup(thr, res->x1.valstack_idx);
73202 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
73203 duk__emit_a_bc(comp_ctx,
73204 DUK_OP_LDREG,
73205 reg_varbind,
73206 reg_temps + 0);
73207 } else {
73208 duk__emit_a_bc(comp_ctx,
73209 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
73210 reg_temps + 0,
73211 rc_varname);
73212 }
73213 } else if (res->t == DUK_IVAL_PROP) {
73214 /* Don't allow a constant for the object (even for a number etc), as
73215 * it goes into the 'A' field of the opcode.
73216 */
73217 duk_regconst_t reg_obj;
73218 duk_regconst_t rc_key;
73219 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
73220 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
73221 duk__emit_a_b_c(comp_ctx,
73222 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
73223 reg_obj,
73224 rc_key,
73225 reg_temps + 0);
73226 } else {
73227 duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
73228 duk__emit_op_only(comp_ctx,
73229 DUK_OP_INVLHS);
73230 }
73231 goto parse_3_or_4;
73232 } else {
73233 /*
73234 * Variant 1
73235 */
73236
73237 DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
73238 duk__ivalue_toplain_ignore(comp_ctx, res);
73239 goto parse_1_or_2;
73240 }
73241 }
73242
73243 parse_1_or_2:
73244 /*
73245 * Parse variant 1 or 2. The first part expression (which differs
73246 * in the variants) has already been parsed and its code emitted.
73247 *
73248 * reg_temps + 0: unused
73249 * reg_temps + 1: unused
73250 */
73251 {
73252 duk_regconst_t rc_cond;
73253 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
73254 duk_int_t pc_jumpto_l3, pc_jumpto_l4;
73255 duk_bool_t expr_c_empty;
73256
73257 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
73258
73259 /* "release" preallocated temps since we won't need them */
73260 temp_reset = reg_temps + 0;
73261 DUK__SETTEMP(comp_ctx, temp_reset);
73262
73263 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
73264
73265 pc_l1 = duk__get_current_pc(comp_ctx);
73266 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
73267 if (duk__expr_is_empty(comp_ctx)) {
73268 /* no need to coerce */
73269 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
73270 pc_jumpto_l4 = -1; /* omitted */
73271 } else {
73272 rc_cond = duk__ivalue_toregconst(comp_ctx, res);
73273 duk__emit_if_false_skip(comp_ctx, rc_cond);
73274 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
73275 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */
73276 }
73277 DUK__SETTEMP(comp_ctx, temp_reset);
73278
73279 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
73280
73281 pc_l2 = duk__get_current_pc(comp_ctx);
73282 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
73283 if (duk__expr_is_empty(comp_ctx)) {
73284 /* no need to coerce */
73285 expr_c_empty = 1;
73286 /* JUMP L1 omitted */
73287 } else {
73288 duk__ivalue_toplain_ignore(comp_ctx, res);
73289 expr_c_empty = 0;
73290 duk__emit_jump(comp_ctx, pc_l1);
73291 }
73292 DUK__SETTEMP(comp_ctx, temp_reset);
73293
73294 comp_ctx->curr_func.allow_regexp_in_adv = 1;
73295 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */
73296
73297 pc_l3 = duk__get_current_pc(comp_ctx);
73298 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73299 if (expr_c_empty) {
73300 duk__emit_jump(comp_ctx, pc_l1);
73301 } else {
73302 duk__emit_jump(comp_ctx, pc_l2);
73303 }
73304 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
73305
73306 pc_l4 = duk__get_current_pc(comp_ctx);
73307
73308 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
73309 "break: %ld->%ld, continue: %ld->%ld",
73310 (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
73311 (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
73312
73313 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
73314 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
73315 duk__patch_jump(comp_ctx,
73316 pc_label_site + 1,
73317 pc_l4); /* break jump */
73318 duk__patch_jump(comp_ctx,
73319 pc_label_site + 2,
73320 expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
73321 }
73322 goto finished;
73323
73324 parse_3_or_4:
73325 /*
73326 * Parse variant 3 or 4.
73327 *
73328 * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
73329 * final property/variable write) has already been emitted. The first
73330 * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
73331 * there to satisfy control flow needs.
73332 *
73333 * For variant 4, if the variable declaration had an initializer
73334 * (e.g. "for (var A = B in C) D;") the code for the assignment
73335 * (B) has already been emitted.
73336 *
73337 * Variables set before entering here:
73338 *
73339 * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
73340 * reg_temps + 0: iteration target value (written to LHS)
73341 * reg_temps + 1: enumerator object
73342 */
73343 {
73344 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
73345 duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
73346 duk_regconst_t reg_target;
73347
73348 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
73349
73350 DUK__SETTEMP(comp_ctx, temp_reset);
73351
73352 /* First we need to insert a jump in the middle of previously
73353 * emitted code to get the control flow right. No jumps can
73354 * cross the position where the jump is inserted. See doc/compiler.rst
73355 * for discussion on the intricacies of control flow and side effects
73356 * for variants 3 and 4.
73357 */
73358
73359 duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
73360 pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */
73361 pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */
73362
73363 /* The code for writing reg_temps + 0 to the left hand side has already
73364 * been emitted.
73365 */
73366
73367 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
73368
73369 duk__advance(comp_ctx); /* eat 'in' */
73370
73371 /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
73372 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
73373 * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
73374 * register (constant not allowed).
73375 */
73376
73377 pc_l2 = duk__get_current_pc(comp_ctx);
73378 reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
73379 duk__emit_b_c(comp_ctx,
73380 DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
73381 reg_temps + 1,
73382 reg_target);
73383 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
73384 DUK__SETTEMP(comp_ctx, temp_reset);
73385
73386 comp_ctx->curr_func.allow_regexp_in_adv = 1;
73387 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */
73388
73389 pc_l3 = duk__get_current_pc(comp_ctx);
73390 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73391 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
73392
73393 /* NEXTENUM needs a jump slot right after the main opcode.
73394 * We need the code emitter to reserve the slot: if there's
73395 * target shuffling, the target shuffle opcodes must happen
73396 * after the jump slot (for NEXTENUM the shuffle opcodes are
73397 * not needed if the enum is finished).
73398 */
73399 pc_l4 = duk__get_current_pc(comp_ctx);
73400 duk__emit_b_c(comp_ctx,
73401 DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
73402 reg_temps + 0,
73403 reg_temps + 1);
73404 pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
73405 duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
73406
73407 pc_l5 = duk__get_current_pc(comp_ctx);
73408
73409 /* XXX: since the enumerator may be a memory expensive object,
73410 * perhaps clear it explicitly here? If so, break jump must
73411 * go through this clearing operation.
73412 */
73413
73414 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
73415 "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
73416 "break: %ld->%ld, continue: %ld->%ld",
73417 (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
73418 (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
73419 (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
73420
73421 duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
73422 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
73423 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
73424 duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
73425 duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */
73426 duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */
73427 }
73428 goto finished;
73429
73430 finished:
73431 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
73432 return;
73433
73434 syntax_error:
73435 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
73436 DUK_WO_NORETURN(return;);
73437}
73438
73439DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
73440 duk_hthread *thr = comp_ctx->thr;
73441 duk_regconst_t temp_at_loop;
73442 duk_regconst_t rc_switch; /* reg/const for switch value */
73443 duk_regconst_t rc_case; /* reg/const for case value */
73444 duk_regconst_t reg_temp; /* general temp register */
73445 duk_int_t pc_prevcase = -1;
73446 duk_int_t pc_prevstmt = -1;
73447 duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
73448
73449 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
73450
73451 /*
73452 * Switch is pretty complicated because of several conflicting concerns:
73453 *
73454 * - Want to generate code without an intermediate representation,
73455 * i.e., in one go
73456 *
73457 * - Case selectors are expressions, not values, and may thus e.g. throw
73458 * exceptions (which causes evaluation order concerns)
73459 *
73460 * - Evaluation semantics of case selectors and default clause need to be
73461 * carefully implemented to provide correct behavior even with case value
73462 * side effects
73463 *
73464 * - Fall through case and default clauses; avoiding dead JUMPs if case
73465 * ends with an unconditional jump (a break or a continue)
73466 *
73467 * - The same case value may occur multiple times, but evaluation rules
73468 * only process the first match before switching to a "propagation" mode
73469 * where case values are no longer evaluated
73470 *
73471 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
73472 * discussion.
73473 */
73474
73475 duk__advance(comp_ctx);
73476 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
73477 rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73478 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */
73479 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
73480
73481 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
73482
73483 temp_at_loop = DUK__GETTEMP(comp_ctx);
73484
73485 for (;;) {
73486 duk_int_t num_stmts;
73487 duk_small_uint_t tok;
73488
73489 /* sufficient for keeping temp reg numbers in check */
73490 DUK__SETTEMP(comp_ctx, temp_at_loop);
73491
73492 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
73493 break;
73494 }
73495
73496 /*
73497 * Parse a case or default clause.
73498 */
73499
73500 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
73501 /*
73502 * Case clause.
73503 *
73504 * Note: cannot use reg_case as a temp register (for SEQ target)
73505 * because it may be a constant.
73506 */
73507
73508 duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
73509 * evaluation and checking
73510 */
73511
73512 duk__advance(comp_ctx);
73513 rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73514 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
73515
73516 reg_temp = DUK__ALLOCTEMP(comp_ctx);
73517 duk__emit_a_b_c(comp_ctx,
73518 DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST,
73519 reg_temp,
73520 rc_switch,
73521 rc_case);
73522 duk__emit_if_true_skip(comp_ctx, reg_temp);
73523
73524 /* jump to next case clause */
73525 pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
73526
73527 /* statements go here (if any) on next loop */
73528 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
73529 /*
73530 * Default clause.
73531 */
73532
73533 if (pc_default >= 0) {
73534 goto syntax_error;
73535 }
73536 duk__advance(comp_ctx);
73537 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
73538
73539 /* Fix for https://github.com/svaarala/duktape/issues/155:
73540 * If 'default' is first clause (detected by pc_prevcase < 0)
73541 * we need to ensure we stay in the matching chain.
73542 */
73543 if (pc_prevcase < 0) {
73544 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
73545 pc_prevcase = duk__emit_jump_empty(comp_ctx);
73546 }
73547
73548 /* default clause matches next statement list (if any) */
73549 pc_default = -2;
73550 } else {
73551 /* Code is not accepted before the first case/default clause */
73552 goto syntax_error;
73553 }
73554
73555 /*
73556 * Parse code after the clause. Possible terminators are
73557 * 'case', 'default', and '}'.
73558 *
73559 * Note that there may be no code at all, not even an empty statement,
73560 * between case clauses. This must be handled just like an empty statement
73561 * (omitting seemingly pointless JUMPs), to avoid situations like
73562 * test-bug-case-fallthrough.js.
73563 */
73564
73565 num_stmts = 0;
73566 if (pc_default == -2) {
73567 pc_default = duk__get_current_pc(comp_ctx);
73568 }
73569
73570 /* Note: this is correct even for default clause statements:
73571 * they participate in 'fall-through' behavior even if the
73572 * default clause is in the middle.
73573 */
73574 duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
73575 * after a case matches.
73576 */
73577
73578 for (;;) {
73579 tok = comp_ctx->curr_token.t;
73580 if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
73581 tok == DUK_TOK_RCURLY) {
73582 break;
73583 }
73584 num_stmts++;
73585 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73586 }
73587
73588 /* fall-through jump to next code of next case (backpatched) */
73589 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
73590
73591 /* XXX: would be nice to omit this jump when the jump is not
73592 * reachable, at least in the obvious cases (such as the case
73593 * ending with a 'break'.
73594 *
73595 * Perhaps duk__parse_stmt() could provide some info on whether
73596 * the statement is a "dead end"?
73597 *
73598 * If implemented, just set pc_prevstmt to -1 when not needed.
73599 */
73600 }
73601
73602 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
73603 comp_ctx->curr_func.allow_regexp_in_adv = 1;
73604 duk__advance(comp_ctx); /* Allow RegExp as part of next stmt. */
73605
73606 /* default case control flow patchup; note that if pc_prevcase < 0
73607 * (i.e. no case clauses), control enters default case automatically.
73608 */
73609 if (pc_default >= 0) {
73610 /* default case exists: go there if no case matches */
73611 duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
73612 } else {
73613 /* default case does not exist, or no statements present
73614 * after default case: finish case evaluation
73615 */
73616 duk__patch_jump_here(comp_ctx, pc_prevcase);
73617 }
73618
73619 /* fall-through control flow patchup; note that pc_prevstmt may be
73620 * < 0 (i.e. no case clauses), in which case this is a no-op.
73621 */
73622 duk__patch_jump_here(comp_ctx, pc_prevstmt);
73623
73624 /* continue jump not patched, an INVALID opcode remains there */
73625 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
73626
73627 /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
73628 * then jump here. The double jump will be eliminated by a
73629 * peephole pass, resulting in an optimal jump here. The label
73630 * site jumps will remain in bytecode and will waste code size.
73631 */
73632
73633 return;
73634
73635 syntax_error:
73636 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
73637 DUK_WO_NORETURN(return;);
73638}
73639
73640DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
73641 duk_regconst_t temp_reset;
73642 duk_regconst_t rc_cond;
73643 duk_int_t pc_jump_false;
73644
73645 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
73646
73647 temp_reset = DUK__GETTEMP(comp_ctx);
73648
73649 duk__advance(comp_ctx); /* eat 'if' */
73650 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
73651
73652 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73653 duk__emit_if_true_skip(comp_ctx, rc_cond);
73654 pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */
73655 DUK__SETTEMP(comp_ctx, temp_reset);
73656
73657 comp_ctx->curr_func.allow_regexp_in_adv = 1;
73658 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */
73659
73660 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73661
73662 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
73663 * construct, so greedy matching is correct here.
73664 */
73665
73666 if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
73667 duk_int_t pc_jump_end;
73668
73669 DUK_DDD(DUK_DDDPRINT("if has else part"));
73670
73671 duk__advance(comp_ctx);
73672
73673 pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */
73674 duk__patch_jump_here(comp_ctx, pc_jump_false);
73675
73676 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73677
73678 duk__patch_jump_here(comp_ctx, pc_jump_end);
73679 } else {
73680 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
73681
73682 duk__patch_jump_here(comp_ctx, pc_jump_false);
73683 }
73684
73685 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
73686}
73687
73688DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
73689 duk_regconst_t rc_cond;
73690 duk_int_t pc_start;
73691
73692 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
73693
73694 duk__advance(comp_ctx); /* Eat 'do'; allow RegExp as part of next stmt. */
73695
73696 pc_start = duk__get_current_pc(comp_ctx);
73697 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73698 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
73699
73700 duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
73701 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
73702
73703 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73704 duk__emit_if_false_skip(comp_ctx, rc_cond);
73705 duk__emit_jump(comp_ctx, pc_start);
73706 /* no need to reset temps, as we're finished emitting code */
73707
73708 comp_ctx->curr_func.allow_regexp_in_adv = 1; /* Allow RegExp as part of next stmt. */
73709 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
73710
73711 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
73712
73713 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
73714}
73715
73716DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
73717 duk_regconst_t temp_reset;
73718 duk_regconst_t rc_cond;
73719 duk_int_t pc_start;
73720 duk_int_t pc_jump_false;
73721
73722 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
73723
73724 temp_reset = DUK__GETTEMP(comp_ctx);
73725
73726 duk__advance(comp_ctx); /* eat 'while' */
73727
73728 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
73729
73730 pc_start = duk__get_current_pc(comp_ctx);
73731 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
73732
73733 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73734 duk__emit_if_true_skip(comp_ctx, rc_cond);
73735 pc_jump_false = duk__emit_jump_empty(comp_ctx);
73736 DUK__SETTEMP(comp_ctx, temp_reset);
73737
73738 comp_ctx->curr_func.allow_regexp_in_adv = 1;
73739 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */
73740
73741 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
73742 duk__emit_jump(comp_ctx, pc_start);
73743
73744 duk__patch_jump_here(comp_ctx, pc_jump_false);
73745 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
73746
73747 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
73748}
73749
73750DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
73751 duk_hthread *thr = comp_ctx->thr;
73752 duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
73753 duk_int_t label_id;
73754 duk_int_t label_catch_depth;
73755 duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
73756 duk_bool_t label_is_closest;
73757
73758 DUK_UNREF(res);
73759
73760 duk__advance(comp_ctx); /* eat 'break' or 'continue' */
73761
73762 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
73763 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
73764 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
73765 /* break/continue without label */
73766
73767 duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
73768 } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
73769 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
73770 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
73771 duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
73772 duk__advance(comp_ctx);
73773 } else {
73774 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
73775 DUK_WO_NORETURN(return;);
73776 }
73777
73778 /* Use a fast break/continue when possible. A fast break/continue is
73779 * just a jump to the LABEL break/continue jump slot, which then jumps
73780 * to an appropriate place (for break, going through ENDLABEL correctly).
73781 * The peephole optimizer will optimize the jump to a direct one.
73782 */
73783
73784 if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
73785 label_is_closest) {
73786 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
73787 "label_catch_depth=%ld, catch_depth=%ld "
73788 "-> use fast variant (direct jump)",
73789 (long) is_break, (long) label_id, (long) label_is_closest,
73790 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
73791
73792 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
73793 } else {
73794 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
73795 "label_catch_depth=%ld, catch_depth=%ld "
73796 "-> use slow variant (longjmp)",
73797 (long) is_break, (long) label_id, (long) label_is_closest,
73798 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
73799
73800 duk__emit_bc(comp_ctx,
73801 is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE,
73802 (duk_regconst_t) label_id);
73803 }
73804}
73805
73806DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
73807 duk_hthread *thr = comp_ctx->thr;
73808 duk_regconst_t rc_val;
73809
73810 duk__advance(comp_ctx); /* eat 'return' */
73811
73812 /* A 'return' statement is only allowed inside an actual function body,
73813 * not as part of eval or global code.
73814 */
73815 if (!comp_ctx->curr_func.is_function) {
73816 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
73817 DUK_WO_NORETURN(return;);
73818 }
73819
73820 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
73821 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
73822 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
73823 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
73824 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
73825 } else {
73826 duk_int_t pc_before_expr;
73827 duk_int_t pc_after_expr;
73828
73829 DUK_DDD(DUK_DDDPRINT("return with a value"));
73830
73831 DUK_UNREF(pc_before_expr);
73832 DUK_UNREF(pc_after_expr);
73833
73834 pc_before_expr = duk__get_current_pc(comp_ctx);
73835 rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73836 pc_after_expr = duk__get_current_pc(comp_ctx);
73837
73838 /* Tail call check: if last opcode emitted was CALL, and
73839 * the context allows it, add a tailcall flag to the CALL.
73840 * This doesn't guarantee that a tail call will be allowed at
73841 * runtime, so the RETURN must still be emitted. (Duktape
73842 * 0.10.0 avoided this and simulated a RETURN if a tail call
73843 * couldn't be used at runtime; but this didn't work
73844 * correctly with a thread yield/resume, see
73845 * test-bug-tailcall-thread-yield-resume.js for discussion.)
73846 *
73847 * In addition to the last opcode being CALL, we also need to
73848 * be sure that 'rc_val' is the result register of the CALL.
73849 * For instance, for the expression 'return 0, (function ()
73850 * { return 1; }), 2' the last opcode emitted is CALL (no
73851 * bytecode is emitted for '2') but 'rc_val' indicates
73852 * constant '2'. Similarly if '2' is replaced by a register
73853 * bound variable, no opcodes are emitted but tail call would
73854 * be incorrect.
73855 *
73856 * This is tricky and easy to get wrong. It would be best to
73857 * track enough expression metadata to check that 'rc_val' came
73858 * from that last CALL instruction. We don't have that metadata
73859 * now, so we check that 'rc_val' is a temporary register result
73860 * (not a constant or a register bound variable). There should
73861 * be no way currently for 'rc_val' to be a temporary for an
73862 * expression following the CALL instruction without emitting
73863 * some opcodes following the CALL. This proxy check is used
73864 * below.
73865 *
73866 * See: test-bug-comma-expr-gh131.js.
73867 *
73868 * The non-standard 'caller' property disables tail calls
73869 * because they pose some special cases which haven't been
73870 * fixed yet.
73871 */
73872
73873#if defined(DUK_USE_TAILCALL)
73874 if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
73875 pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
73876 duk_compiler_instr *instr;
73877 duk_instr_t ins;
73878 duk_small_uint_t op;
73879
73880 instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
73881 DUK_ASSERT(instr != NULL);
73882
73883 ins = instr->ins;
73884 op = (duk_small_uint_t) DUK_DEC_OP(ins);
73885 if ((op & ~0x0fU) == DUK_OP_CALL0 &&
73886 DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) {
73887 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
73888 "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
73889 "and last instruction is a CALL "
73890 "-> change to TAILCALL"));
73891 ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL);
73892 instr->ins = ins;
73893 }
73894 }
73895#endif /* DUK_USE_TAILCALL */
73896
73897 if (DUK__ISREG(rc_val)) {
73898 duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val);
73899 } else {
73900 rc_val = DUK__REMOVECONST(rc_val);
73901 if (duk__const_needs_refcount(comp_ctx, rc_val)) {
73902 duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val);
73903 } else {
73904 duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val);
73905 }
73906 }
73907 }
73908}
73909
73910DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
73911 duk_regconst_t reg_val;
73912
73913 duk__advance(comp_ctx); /* eat 'throw' */
73914
73915 /* Unlike break/continue, throw statement does not allow an empty value. */
73916
73917 if (comp_ctx->curr_token.lineterm) {
73918 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
73919 DUK_WO_NORETURN(return;);
73920 }
73921
73922 reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
73923 duk__emit_bc(comp_ctx,
73924 DUK_OP_THROW,
73925 reg_val);
73926}
73927
73928DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
73929 duk_hthread *thr = comp_ctx->thr;
73930 duk_regconst_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
73931 duk_regconst_t rc_varname = 0;
73932 duk_small_uint_t trycatch_flags = 0;
73933 duk_int_t pc_ldconst = -1;
73934 duk_int_t pc_trycatch = -1;
73935 duk_int_t pc_catch = -1;
73936 duk_int_t pc_finally = -1;
73937
73938 DUK_UNREF(res);
73939
73940 /*
73941 * See the following documentation for discussion:
73942 *
73943 * doc/execution.rst: control flow details
73944 *
73945 * Try, catch, and finally "parts" are Blocks, not Statements, so
73946 * they must always be delimited by curly braces. This is unlike e.g.
73947 * the if statement, which accepts any Statement. This eliminates any
73948 * questions of matching parts of nested try statements. The Block
73949 * parsing is implemented inline here (instead of calling out).
73950 *
73951 * Finally part has a 'let scoped' variable, which requires a few kinks
73952 * here.
73953 */
73954
73955 comp_ctx->curr_func.catch_depth++;
73956
73957 duk__advance(comp_ctx); /* eat 'try' */
73958
73959 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
73960
73961 /* The target for this LDCONST may need output shuffling, but we assume
73962 * that 'pc_ldconst' will be the LDCONST that we can patch later. This
73963 * should be the case because there's no input shuffling. (If there's
73964 * no catch clause, this LDCONST will be replaced with a NOP.)
73965 */
73966 pc_ldconst = duk__get_current_pc(comp_ctx);
73967 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
73968
73969 pc_trycatch = duk__get_current_pc(comp_ctx);
73970 duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */
73971 duk__emit_invalid(comp_ctx); /* jump for 'catch' case */
73972 duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */
73973
73974 /* try part */
73975 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
73976 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
73977 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
73978 duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY);
73979
73980 if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
73981 /*
73982 * The catch variable must be updated to reflect the new allocated
73983 * register for the duration of the catch clause. We need to store
73984 * and restore the original value for the varmap entry (if any).
73985 */
73986
73987 /*
73988 * Note: currently register bindings must be fixed for the entire
73989 * function. So, even though the catch variable is in a register
73990 * we know, we must use an explicit environment record and slow path
73991 * accesses to read/write the catch binding to make closures created
73992 * within the catch clause work correctly. This restriction should
73993 * be fixable (at least in common cases) later.
73994 *
73995 * See: test-bug-catch-binding-2.js.
73996 *
73997 * XXX: improve to get fast path access to most catch clauses.
73998 */
73999
74000 duk_hstring *h_var;
74001 duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
74002
74003 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(thr)));
74004
74005 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
74006
74007 pc_catch = duk__get_current_pc(comp_ctx);
74008
74009 duk__advance(comp_ctx);
74010 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
74011
74012 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
74013 /* Identifier, i.e. don't allow reserved words */
74014 goto syntax_error;
74015 }
74016 h_var = comp_ctx->curr_token.str1;
74017 DUK_ASSERT(h_var != NULL);
74018
74019 duk_push_hstring(thr, h_var); /* keep in on valstack, use borrowed ref below */
74020
74021 if (comp_ctx->curr_func.is_strict &&
74022 ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
74023 (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
74024 DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
74025 goto syntax_error;
74026 }
74027
74028 duk_dup_top(thr);
74029 rc_varname = duk__getconst(comp_ctx);
74030 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
74031 (unsigned long) rc_varname, (long) rc_varname));
74032
74033 duk__advance(comp_ctx);
74034 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
74035
74036 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
74037
74038 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
74039 (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
74040
74041 duk_dup_top(thr);
74042 duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
74043 if (duk_is_undefined(thr, -1)) {
74044 varmap_value = -2;
74045 } else if (duk_is_null(thr, -1)) {
74046 varmap_value = -1;
74047 } else {
74048 DUK_ASSERT(duk_is_number(thr, -1));
74049 varmap_value = duk_get_int(thr, -1);
74050 DUK_ASSERT(varmap_value >= 0);
74051 }
74052 duk_pop(thr);
74053
74054#if 0
74055 /* It'd be nice to do something like this - but it doesn't
74056 * work for closures created inside the catch clause.
74057 */
74058 duk_dup_top(thr);
74059 duk_push_int(thr, (duk_int_t) (reg_catch + 0));
74060 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
74061#endif
74062 duk_dup_top(thr);
74063 duk_push_null(thr);
74064 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
74065
74066 duk__emit_a_bc(comp_ctx,
74067 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
74068 reg_catch + 0 /*value*/,
74069 rc_varname /*varname*/);
74070
74071 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
74072 (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
74073
74074 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
74075 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
74076
74077 if (varmap_value == -2) {
74078 /* not present */
74079 duk_del_prop(thr, comp_ctx->curr_func.varmap_idx);
74080 } else {
74081 if (varmap_value == -1) {
74082 duk_push_null(thr);
74083 } else {
74084 DUK_ASSERT(varmap_value >= 0);
74085 duk_push_int(thr, varmap_value);
74086 }
74087 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
74088 }
74089 /* varname is popped by above code */
74090
74091 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
74092 (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
74093
74094 duk__emit_op_only(comp_ctx,
74095 DUK_OP_ENDCATCH);
74096
74097 /*
74098 * XXX: for now, indicate that an expensive catch binding
74099 * declarative environment is always needed. If we don't
74100 * need it, we don't need the const_varname either.
74101 */
74102
74103 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
74104
74105 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(thr)));
74106 }
74107
74108 if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
74109 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
74110
74111 pc_finally = duk__get_current_pc(comp_ctx);
74112
74113 duk__advance(comp_ctx);
74114
74115 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
74116 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
74117 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
74118 duk__emit_abc(comp_ctx,
74119 DUK_OP_ENDFIN,
74120 reg_catch); /* rethrow */
74121 }
74122
74123 if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
74124 !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
74125 /* must have catch and/or finally */
74126 goto syntax_error;
74127 }
74128
74129 /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
74130 * will replace the LDCONST with a NOP. For any actual constant (including
74131 * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
74132 */
74133
74134 duk__patch_trycatch(comp_ctx,
74135 pc_ldconst,
74136 pc_trycatch,
74137 reg_catch,
74138 rc_varname,
74139 trycatch_flags);
74140
74141 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
74142 DUK_ASSERT(pc_catch >= 0);
74143 duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
74144 }
74145
74146 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
74147 DUK_ASSERT(pc_finally >= 0);
74148 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
74149 } else {
74150 /* without finally, the second jump slot is used to jump to end of stmt */
74151 duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
74152 }
74153
74154 comp_ctx->curr_func.catch_depth--;
74155 return;
74156
74157 syntax_error:
74158 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
74159 DUK_WO_NORETURN(return;);
74160}
74161
74162DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
74163 duk_int_t pc_trycatch;
74164 duk_int_t pc_finished;
74165 duk_regconst_t reg_catch;
74166 duk_small_uint_t trycatch_flags;
74167
74168 if (comp_ctx->curr_func.is_strict) {
74169 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
74170 DUK_WO_NORETURN(return;);
74171 }
74172
74173 comp_ctx->curr_func.catch_depth++;
74174
74175 duk__advance(comp_ctx); /* eat 'with' */
74176
74177 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
74178
74179 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
74180 duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
74181 comp_ctx->curr_func.allow_regexp_in_adv = 1;
74182 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */
74183
74184 pc_trycatch = duk__get_current_pc(comp_ctx);
74185 trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
74186 duk__emit_a_bc(comp_ctx,
74187 DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
74188 (duk_regconst_t) trycatch_flags /*a*/,
74189 reg_catch /*bc*/);
74190 duk__emit_invalid(comp_ctx); /* catch jump */
74191 duk__emit_invalid(comp_ctx); /* finished jump */
74192
74193 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
74194 duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY);
74195
74196 pc_finished = duk__get_current_pc(comp_ctx);
74197
74198 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
74199
74200 comp_ctx->curr_func.catch_depth--;
74201}
74202
74203DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
74204 /* if a site already exists, nop: max one label site per statement */
74205 if (label_id >= 0) {
74206 return label_id;
74207 }
74208
74209 label_id = comp_ctx->curr_func.label_next++;
74210 DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
74211
74212 duk__emit_bc(comp_ctx,
74213 DUK_OP_LABEL,
74214 (duk_regconst_t) label_id);
74215 duk__emit_invalid(comp_ctx);
74216 duk__emit_invalid(comp_ctx);
74217
74218 return label_id;
74219}
74220
74221/* Parse a single statement.
74222 *
74223 * Creates a label site (with an empty label) automatically for iteration
74224 * statements. Also "peels off" any label statements for explicit labels.
74225 */
74226DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
74227 duk_hthread *thr = comp_ctx->thr;
74228 duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
74229 duk_regconst_t temp_at_entry;
74230 duk_size_t labels_len_at_entry;
74231 duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
74232 duk_int_t stmt_id;
74233 duk_small_uint_t stmt_flags = 0;
74234 duk_int_t label_id = -1;
74235 duk_small_uint_t tok;
74236 duk_bool_t test_func_decl;
74237
74238 DUK__RECURSION_INCREASE(comp_ctx, thr);
74239
74240 temp_at_entry = DUK__GETTEMP(comp_ctx);
74241 pc_at_entry = duk__get_current_pc(comp_ctx);
74242 labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx);
74243 stmt_id = comp_ctx->curr_func.stmt_next++;
74244 dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
74245
74246 DUK_UNREF(stmt_id);
74247
74248 DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
74249 "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
74250 (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
74251 (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
74252 (long) comp_ctx->curr_func.catch_depth));
74253
74254 /* The directive prologue flag is cleared by default so that it is
74255 * unset for any recursive statement parsing. It is only "revived"
74256 * if a directive is detected. (We could also make directives only
74257 * allowed if 'allow_source_elem' was true.)
74258 */
74259 comp_ctx->curr_func.in_directive_prologue = 0;
74260
74261 retry_parse:
74262
74263 DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
74264 (long) stmt_id, (long) label_id, (long) allow_source_elem,
74265 (long) comp_ctx->curr_func.catch_depth));
74266
74267 /*
74268 * Detect iteration statements; if encountered, establish an
74269 * empty label.
74270 */
74271
74272 tok = comp_ctx->curr_token.t;
74273 if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
74274 tok == DUK_TOK_SWITCH) {
74275 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
74276
74277 label_id = duk__stmt_label_site(comp_ctx, label_id);
74278 duk__add_label(comp_ctx,
74279 DUK_HTHREAD_STRING_EMPTY_STRING(thr),
74280 pc_at_entry /*pc_label*/,
74281 label_id);
74282 }
74283
74284 /*
74285 * Main switch for statement / source element type.
74286 */
74287
74288 switch (comp_ctx->curr_token.t) {
74289 case DUK_TOK_FUNCTION: {
74290 /*
74291 * Function declaration, function expression, or (non-standard)
74292 * function statement.
74293 *
74294 * The E5 specification only allows function declarations at
74295 * the top level (in "source elements"). An ExpressionStatement
74296 * is explicitly not allowed to begin with a "function" keyword
74297 * (E5 Section 12.4). Hence any non-error semantics for such
74298 * non-top-level statements are non-standard. Duktape semantics
74299 * for function statements are modelled after V8, see
74300 * test-dev-func-decl-outside-top.js.
74301 */
74302 test_func_decl = allow_source_elem;
74303#if defined(DUK_USE_NONSTD_FUNC_STMT)
74304 /* Lenient: allow function declarations outside top level in both
74305 * strict and non-strict modes. However, don't allow labelled
74306 * function declarations in strict mode.
74307 */
74308 test_func_decl = test_func_decl ||
74309 !comp_ctx->curr_func.is_strict ||
74310 label_id < 0;
74311#endif /* DUK_USE_NONSTD_FUNC_STMT */
74312 /* Strict: never allow function declarations outside top level. */
74313 if (test_func_decl) {
74314 /* FunctionDeclaration: not strictly a statement but handled as such.
74315 *
74316 * O(depth^2) parse count for inner functions is handled by recording a
74317 * lexer offset on the first compilation pass, so that the function can
74318 * be efficiently skipped on the second pass. This is encapsulated into
74319 * duk__parse_func_like_fnum().
74320 */
74321
74322 duk_int_t fnum;
74323#if defined(DUK_USE_ASSERTIONS)
74324 duk_idx_t top_before;
74325#endif
74326
74327 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
74328
74329#if defined(DUK_USE_ASSERTIONS)
74330 top_before = duk_get_top(thr);
74331#endif
74332
74333 duk__advance(comp_ctx); /* eat 'function' */
74334 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1);
74335
74336 /* The value stack convention here is a bit odd: the function
74337 * name is only pushed on pass 1 (in_scanning), and is needed
74338 * to process function declarations.
74339 */
74340 if (comp_ctx->curr_func.in_scanning) {
74341 duk_uarridx_t n;
74342
74343#if defined(DUK_USE_ASSERTIONS)
74344 DUK_ASSERT(duk_get_top(thr) == top_before + 1);
74345#endif
74346 DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld",
74347 duk_get_tval(thr, -1), (long) fnum));
74348 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
74349 /* funcname is at index -1 */
74350 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
74351 duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
74352 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
74353 } else {
74354#if defined(DUK_USE_ASSERTIONS)
74355 DUK_ASSERT(duk_get_top(thr) == top_before);
74356#endif
74357 }
74358
74359 /* no statement value (unlike function expression) */
74360 stmt_flags = 0;
74361 break;
74362 } else {
74363 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
74364 DUK_WO_NORETURN(return;);
74365 }
74366 break;
74367 }
74368 case DUK_TOK_LCURLY: {
74369 DUK_DDD(DUK_DDDPRINT("block statement"));
74370 duk__advance(comp_ctx);
74371 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
74372 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
74373 if (label_id >= 0) {
74374 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
74375 }
74376 stmt_flags = 0;
74377 break;
74378 }
74379 case DUK_TOK_CONST: {
74380 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
74381 duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
74382 stmt_flags = DUK__HAS_TERM;
74383 break;
74384 }
74385 case DUK_TOK_VAR: {
74386 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
74387 duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
74388 stmt_flags = DUK__HAS_TERM;
74389 break;
74390 }
74391 case DUK_TOK_SEMICOLON: {
74392 /* empty statement with an explicit semicolon */
74393 DUK_DDD(DUK_DDDPRINT("empty statement"));
74394 stmt_flags = DUK__HAS_TERM;
74395 break;
74396 }
74397 case DUK_TOK_IF: {
74398 DUK_DDD(DUK_DDDPRINT("if statement"));
74399 duk__parse_if_stmt(comp_ctx, res);
74400 if (label_id >= 0) {
74401 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
74402 }
74403 stmt_flags = 0;
74404 break;
74405 }
74406 case DUK_TOK_DO: {
74407 /*
74408 * Do-while statement is mostly trivial, but there is special
74409 * handling for automatic semicolon handling (triggered by the
74410 * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
74411 *
74412 * https://bugs.ecmascript.org/show_bug.cgi?id=8
74413 *
74414 * See doc/compiler.rst for details.
74415 */
74416 DUK_DDD(DUK_DDDPRINT("do statement"));
74417 DUK_ASSERT(label_id >= 0);
74418 duk__update_label_flags(comp_ctx,
74419 label_id,
74420 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
74421 duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
74422 stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
74423 break;
74424 }
74425 case DUK_TOK_WHILE: {
74426 DUK_DDD(DUK_DDDPRINT("while statement"));
74427 DUK_ASSERT(label_id >= 0);
74428 duk__update_label_flags(comp_ctx,
74429 label_id,
74430 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
74431 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
74432 stmt_flags = 0;
74433 break;
74434 }
74435 case DUK_TOK_FOR: {
74436 /*
74437 * For/for-in statement is complicated to parse because
74438 * determining the statement type (three-part for vs. a
74439 * for-in) requires potential backtracking.
74440 *
74441 * See the helper for the messy stuff.
74442 */
74443 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
74444 DUK_ASSERT(label_id >= 0);
74445 duk__update_label_flags(comp_ctx,
74446 label_id,
74447 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
74448 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
74449 stmt_flags = 0;
74450 break;
74451 }
74452 case DUK_TOK_CONTINUE:
74453 case DUK_TOK_BREAK: {
74454 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
74455 duk__parse_break_or_continue_stmt(comp_ctx, res);
74456 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
74457 break;
74458 }
74459 case DUK_TOK_RETURN: {
74460 DUK_DDD(DUK_DDDPRINT("return statement"));
74461 duk__parse_return_stmt(comp_ctx, res);
74462 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
74463 break;
74464 }
74465 case DUK_TOK_WITH: {
74466 DUK_DDD(DUK_DDDPRINT("with statement"));
74467 comp_ctx->curr_func.with_depth++;
74468 duk__parse_with_stmt(comp_ctx, res);
74469 if (label_id >= 0) {
74470 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
74471 }
74472 comp_ctx->curr_func.with_depth--;
74473 stmt_flags = 0;
74474 break;
74475 }
74476 case DUK_TOK_SWITCH: {
74477 /*
74478 * The switch statement is pretty messy to compile.
74479 * See the helper for details.
74480 */
74481 DUK_DDD(DUK_DDDPRINT("switch statement"));
74482 DUK_ASSERT(label_id >= 0);
74483 duk__update_label_flags(comp_ctx,
74484 label_id,
74485 DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
74486 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
74487 stmt_flags = 0;
74488 break;
74489 }
74490 case DUK_TOK_THROW: {
74491 DUK_DDD(DUK_DDDPRINT("throw statement"));
74492 duk__parse_throw_stmt(comp_ctx, res);
74493 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
74494 break;
74495 }
74496 case DUK_TOK_TRY: {
74497 DUK_DDD(DUK_DDDPRINT("try statement"));
74498 duk__parse_try_stmt(comp_ctx, res);
74499 stmt_flags = 0;
74500 break;
74501 }
74502 case DUK_TOK_DEBUGGER: {
74503 duk__advance(comp_ctx);
74504#if defined(DUK_USE_DEBUGGER_SUPPORT)
74505 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
74506 duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER);
74507#else
74508 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
74509#endif
74510 stmt_flags = DUK__HAS_TERM;
74511 break;
74512 }
74513 default: {
74514 /*
74515 * Else, must be one of:
74516 * - ExpressionStatement, possibly a directive (String)
74517 * - LabelledStatement (Identifier followed by ':')
74518 *
74519 * Expressions beginning with 'function' keyword are covered by a case
74520 * above (such expressions are not allowed in standard E5 anyway).
74521 * Also expressions starting with '{' are interpreted as block
74522 * statements. See E5 Section 12.4.
74523 *
74524 * Directive detection is tricky; see E5 Section 14.1 on directive
74525 * prologue. A directive is an expression statement with a single
74526 * string literal and an explicit or automatic semicolon. Escape
74527 * characters are significant and no parens etc are allowed:
74528 *
74529 * 'use strict'; // valid 'use strict' directive
74530 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
74531 * ('use strict'); // not a valid directive
74532 *
74533 * The expression is determined to consist of a single string literal
74534 * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
74535 * of a 'use strict' directive is determined to lack any escapes based
74536 * num_escapes count from the lexer. Note that other directives may be
74537 * allowed to contain escapes, so a directive with escapes does not
74538 * terminate a directive prologue.
74539 *
74540 * We rely on the fact that the expression parser will not emit any
74541 * code for a single token expression. However, it will generate an
74542 * intermediate value which we will then successfully ignore.
74543 *
74544 * A similar approach is used for labels.
74545 */
74546
74547 duk_bool_t single_token;
74548
74549 DUK_DDD(DUK_DDDPRINT("expression statement"));
74550 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
74551
74552 single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
74553 comp_ctx->curr_func.led_count == 0); /* no operators */
74554
74555 if (single_token &&
74556 comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
74557 comp_ctx->curr_token.t == DUK_TOK_COLON) {
74558 /*
74559 * Detected label
74560 */
74561
74562 duk_hstring *h_lab;
74563
74564 /* expected ival */
74565 DUK_ASSERT(res->t == DUK_IVAL_VAR);
74566 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
74567 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
74568 h_lab = comp_ctx->prev_token.str1;
74569 DUK_ASSERT(h_lab != NULL);
74570
74571 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
74572 (duk_heaphdr *) h_lab));
74573
74574 duk__advance(comp_ctx); /* eat colon */
74575
74576 label_id = duk__stmt_label_site(comp_ctx, label_id);
74577
74578 duk__add_label(comp_ctx,
74579 h_lab,
74580 pc_at_entry /*pc_label*/,
74581 label_id);
74582
74583 /* a statement following a label cannot be a source element
74584 * (a function declaration).
74585 */
74586 allow_source_elem = 0;
74587
74588 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
74589 goto retry_parse;
74590 }
74591
74592 stmt_flags = 0;
74593
74594 if (dir_prol_at_entry && /* still in prologue */
74595 single_token && /* single string token */
74596 comp_ctx->prev_token.t == DUK_TOK_STRING) {
74597 /*
74598 * Detected a directive
74599 */
74600 duk_hstring *h_dir;
74601
74602 /* expected ival */
74603 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
74604 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
74605 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
74606 h_dir = comp_ctx->prev_token.str1;
74607 DUK_ASSERT(h_dir != NULL);
74608
74609 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
74610
74611 stmt_flags |= DUK__STILL_PROLOGUE;
74612
74613 /* Note: escaped characters differentiate directives */
74614
74615 if (comp_ctx->prev_token.num_escapes > 0) {
74616 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
74617 "but we ignore such directives"));
74618 } else {
74619 /*
74620 * The length comparisons are present to handle
74621 * strings like "use strict\u0000foo" as required.
74622 */
74623
74624 if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
74625 DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict") == 0) {
74626#if defined(DUK_USE_STRICT_DECL)
74627 DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
74628 (long) comp_ctx->curr_func.is_strict, (long) 1));
74629 comp_ctx->curr_func.is_strict = 1;
74630#else
74631 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
74632#endif
74633 } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
74634 DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail") == 0) {
74635 DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
74636 (long) comp_ctx->curr_func.is_notail, (long) 1));
74637 comp_ctx->curr_func.is_notail = 1;
74638 } else {
74639 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
74640 "directive prologue", (duk_hobject *) h_dir));
74641 }
74642 }
74643 } else {
74644 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
74645 "prologue terminated if still active"));
74646 }
74647
74648 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
74649 }
74650 } /* end switch (tok) */
74651
74652 /*
74653 * Statement value handling.
74654 *
74655 * Global code and eval code has an implicit return value
74656 * which comes from the last statement with a value
74657 * (technically a non-"empty" continuation, which is
74658 * different from an empty statement).
74659 *
74660 * Since we don't know whether a later statement will
74661 * override the value of the current statement, we need
74662 * to coerce the statement value to a register allocated
74663 * for implicit return values. In other cases we need
74664 * to coerce the statement value to a plain value to get
74665 * any side effects out (consider e.g. "foo.bar;").
74666 */
74667
74668 /* XXX: what about statements which leave a half-cooked value in 'res'
74669 * but have no stmt value? Any such statements?
74670 */
74671
74672 if (stmt_flags & DUK__HAS_VAL) {
74673 duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
74674 if (reg_stmt_value >= 0) {
74675 duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
74676 } else {
74677 duk__ivalue_toplain_ignore(comp_ctx, res);
74678 }
74679 } else {
74680 ;
74681 }
74682
74683 /*
74684 * Statement terminator check, including automatic semicolon
74685 * handling. After this step, 'curr_tok' should be the first
74686 * token after a possible statement terminator.
74687 */
74688
74689 if (stmt_flags & DUK__HAS_TERM) {
74690 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
74691 DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
74692 duk__advance(comp_ctx);
74693 } else {
74694 if (comp_ctx->curr_token.allow_auto_semi) {
74695 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
74696 } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
74697 /* XXX: make this lenience dependent on flags or strictness? */
74698 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
74699 "even though no lineterm present before next token)"));
74700 } else {
74701 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
74702 DUK_WO_NORETURN(return;);
74703 }
74704 }
74705 } else {
74706 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
74707 }
74708
74709 /*
74710 * Directive prologue tracking.
74711 */
74712
74713 if (stmt_flags & DUK__STILL_PROLOGUE) {
74714 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
74715 comp_ctx->curr_func.in_directive_prologue = 1;
74716 }
74717
74718 /*
74719 * Cleanups (all statement parsing flows through here).
74720 *
74721 * Pop label site and reset labels. Reset 'next temp' to value at
74722 * entry to reuse temps.
74723 */
74724
74725 if (label_id >= 0) {
74726 duk__emit_bc(comp_ctx,
74727 DUK_OP_ENDLABEL,
74728 (duk_regconst_t) label_id);
74729 }
74730
74731 DUK__SETTEMP(comp_ctx, temp_at_entry);
74732
74733 duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
74734
74735 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
74736
74737 DUK__RECURSION_DECREASE(comp_ctx, thr);
74738}
74739
74740/*
74741 * Parse a statement list.
74742 *
74743 * Handles automatic semicolon insertion and implicit return value.
74744 *
74745 * Upon entry, 'curr_tok' should contain the first token of the first
74746 * statement (parsed in the "allow regexp literal" mode). Upon exit,
74747 * 'curr_tok' contains the token following the statement list terminator
74748 * (EOF or closing brace).
74749 */
74750
74751DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after) {
74752 duk_hthread *thr = comp_ctx->thr;
74753 duk_ivalue res_alloc;
74754 duk_ivalue *res = &res_alloc;
74755
74756 /* Setup state. Initial ivalue is 'undefined'. */
74757
74758 duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS);
74759
74760 /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
74761 * intermediate values suffice for parsing of each function. Nesting is needed
74762 * for nested functions (which may occur inside expressions).
74763 */
74764
74765 duk_memzero(&res_alloc, sizeof(res_alloc));
74766 res->t = DUK_IVAL_PLAIN;
74767 res->x1.t = DUK_ISPEC_VALUE;
74768 res->x1.valstack_idx = duk_get_top(thr);
74769 res->x2.valstack_idx = res->x1.valstack_idx + 1;
74770 duk_push_undefined(thr);
74771 duk_push_undefined(thr);
74772
74773 /* Parse statements until a closing token (EOF or '}') is found. */
74774
74775 for (;;) {
74776 /* Check whether statement list ends. */
74777
74778 if (expect_eof) {
74779 if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
74780 break;
74781 }
74782 } else {
74783 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
74784 break;
74785 }
74786 }
74787
74788 /* Check statement type based on the first token type.
74789 *
74790 * Note: expression parsing helpers expect 'curr_tok' to
74791 * contain the first token of the expression upon entry.
74792 */
74793
74794 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
74795
74796 duk__parse_stmt(comp_ctx, res, allow_source_elem);
74797 }
74798
74799 /* RegExp is allowed / not allowed depending on context. For function
74800 * declarations RegExp is allowed because it follows a function
74801 * declaration statement and may appear as part of the next statement.
74802 * For function expressions RegExp is not allowed, and it's possible
74803 * to do something like '(function () {} / 123)'.
74804 */
74805 if (regexp_after) {
74806 comp_ctx->curr_func.allow_regexp_in_adv = 1;
74807 }
74808 duk__advance(comp_ctx);
74809
74810 /* Tear down state. */
74811
74812 duk_pop_2(thr);
74813}
74814
74815/*
74816 * Declaration binding instantiation conceptually happens when calling a
74817 * function; for us it essentially means that function prologue. The
74818 * conceptual process is described in E5 Section 10.5.
74819 *
74820 * We need to keep track of all encountered identifiers to (1) create an
74821 * identifier-to-register map ("varmap"); and (2) detect duplicate
74822 * declarations. Identifiers which are not bound to registers still need
74823 * to be tracked for detecting duplicates. Currently such identifiers
74824 * are put into the varmap with a 'null' value, which is later cleaned up.
74825 *
74826 * To support functions with a large number of variable and function
74827 * declarations, registers are not allocated beyond a certain limit;
74828 * after that limit, variables and functions need slow path access.
74829 * Arguments are currently always register bound, which imposes a hard
74830 * (and relatively small) argument count limit.
74831 *
74832 * Some bindings in E5 are not configurable (= deletable) and almost all
74833 * are mutable (writable). Exceptions are:
74834 *
74835 * - The 'arguments' binding, established only if no shadowing argument
74836 * or function declaration exists. We handle 'arguments' creation
74837 * and binding through an explicit slow path environment record.
74838 *
74839 * - The "name" binding for a named function expression. This is also
74840 * handled through an explicit slow path environment record.
74841 */
74842
74843/* XXX: add support for variables to not be register bound always, to
74844 * handle cases with a very large number of variables?
74845 */
74846
74847DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) {
74848 duk_hthread *thr = comp_ctx->thr;
74849 duk_hstring *h_name;
74850 duk_bool_t configurable_bindings;
74851 duk_uarridx_t num_args;
74852 duk_uarridx_t num_decls;
74853 duk_regconst_t rc_name;
74854 duk_small_uint_t declvar_flags;
74855 duk_uarridx_t i;
74856#if defined(DUK_USE_ASSERTIONS)
74857 duk_idx_t entry_top;
74858#endif
74859
74860#if defined(DUK_USE_ASSERTIONS)
74861 entry_top = duk_get_top(thr);
74862#endif
74863
74864 /*
74865 * Preliminaries
74866 */
74867
74868 configurable_bindings = comp_ctx->curr_func.is_eval;
74869 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
74870
74871 /* varmap is already in comp_ctx->curr_func.varmap_idx */
74872
74873 /*
74874 * Function formal arguments, always bound to registers
74875 * (there's no support for shuffling them now).
74876 */
74877
74878 num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
74879 DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
74880 /* XXX: check num_args */
74881
74882 for (i = 0; i < num_args; i++) {
74883 duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i);
74884 h_name = duk_known_hstring(thr, -1);
74885
74886 if (comp_ctx->curr_func.is_strict) {
74887 if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
74888 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
74889 goto error_argname;
74890 }
74891 duk_dup_top(thr);
74892 if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
74893 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
74894 goto error_argname;
74895 }
74896
74897 /* Ensure argument name is not a reserved word in current
74898 * (final) strictness. Formal argument parsing may not
74899 * catch reserved names if strictness changes during
74900 * parsing.
74901 *
74902 * We only need to do this in strict mode because non-strict
74903 * keyword are always detected in formal argument parsing.
74904 */
74905
74906 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
74907 goto error_argname;
74908 }
74909 }
74910
74911 /* overwrite any previous binding of the same name; the effect is
74912 * that last argument of a certain name wins.
74913 */
74914
74915 /* only functions can have arguments */
74916 DUK_ASSERT(comp_ctx->curr_func.is_function);
74917 duk_push_uarridx(thr, i); /* -> [ ... name index ] */
74918 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
74919
74920 /* no code needs to be emitted, the regs already have values */
74921 }
74922
74923 /* use temp_next for tracking register allocations */
74924 DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args);
74925
74926 /*
74927 * After arguments, allocate special registers (like shuffling temps)
74928 */
74929
74930 if (out_stmt_value_reg) {
74931 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
74932 }
74933 if (comp_ctx->curr_func.needs_shuffle) {
74934 duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
74935 comp_ctx->curr_func.shuffle1 = shuffle_base;
74936 comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
74937 comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
74938 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
74939 (long) comp_ctx->curr_func.shuffle1,
74940 (long) comp_ctx->curr_func.shuffle2,
74941 (long) comp_ctx->curr_func.shuffle3));
74942 }
74943 if (comp_ctx->curr_func.temp_next > 0x100) {
74944 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
74945 goto error_outofregs;
74946 }
74947
74948 /*
74949 * Function declarations
74950 */
74951
74952 num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
74953 DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
74954 (long) num_decls,
74955 (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx)));
74956 for (i = 0; i < num_decls; i += 2) {
74957 duk_int_t decl_type;
74958 duk_int_t fnum;
74959
74960 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
74961 decl_type = duk_to_int(thr, -1);
74962 fnum = decl_type >> 8; /* XXX: macros */
74963 decl_type = decl_type & 0xff;
74964 duk_pop(thr);
74965
74966 if (decl_type != DUK_DECL_TYPE_FUNC) {
74967 continue;
74968 }
74969
74970 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
74971
74972 /* XXX: spilling */
74973 if (comp_ctx->curr_func.is_function) {
74974 duk_regconst_t reg_bind;
74975 duk_dup_top(thr);
74976 if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
74977 /* shadowed; update value */
74978 duk_dup_top(thr);
74979 duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
74980 reg_bind = duk_to_int(thr, -1); /* [ ... name reg_bind ] */
74981 duk__emit_a_bc(comp_ctx,
74982 DUK_OP_CLOSURE,
74983 reg_bind,
74984 (duk_regconst_t) fnum);
74985 } else {
74986 /* function: always register bound */
74987 reg_bind = DUK__ALLOCTEMP(comp_ctx);
74988 duk__emit_a_bc(comp_ctx,
74989 DUK_OP_CLOSURE,
74990 reg_bind,
74991 (duk_regconst_t) fnum);
74992 duk_push_int(thr, (duk_int_t) reg_bind);
74993 }
74994 } else {
74995 /* Function declaration for global/eval code is emitted even
74996 * for duplicates, because of E5 Section 10.5, step 5.e of
74997 * E5.1 (special behavior for variable bound to global object).
74998 *
74999 * DECLVAR will not re-declare a variable as such, but will
75000 * update the binding value.
75001 */
75002
75003 duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
75004 duk_dup_top(thr);
75005 rc_name = duk__getconst(comp_ctx);
75006 duk_push_null(thr);
75007
75008 duk__emit_a_bc(comp_ctx,
75009 DUK_OP_CLOSURE,
75010 reg_temp,
75011 (duk_regconst_t) fnum);
75012
75013 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
75014 DUK_PROPDESC_FLAG_ENUMERABLE |
75015 DUK_BC_DECLVAR_FLAG_FUNC_DECL;
75016
75017 if (configurable_bindings) {
75018 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
75019 }
75020
75021 duk__emit_a_b_c(comp_ctx,
75022 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
75023 (duk_regconst_t) declvar_flags /*flags*/,
75024 rc_name /*name*/,
75025 reg_temp /*value*/);
75026
75027 DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
75028 }
75029
75030 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
75031 (duk_tval *) duk_get_tval(thr, -2),
75032 (duk_tval *) duk_get_tval(thr, -1)));
75033
75034#if defined(DUK_USE_FASTINT)
75035 DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1)));
75036#endif
75037 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
75038 }
75039
75040 /*
75041 * 'arguments' binding is special; if a shadowing argument or
75042 * function declaration exists, an arguments object will
75043 * definitely not be needed, regardless of whether the identifier
75044 * 'arguments' is referenced inside the function body.
75045 */
75046
75047 if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
75048 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
75049 "-> arguments object creation can be skipped"));
75050 comp_ctx->curr_func.is_arguments_shadowed = 1;
75051 }
75052
75053 /*
75054 * Variable declarations.
75055 *
75056 * Unlike function declarations, variable declaration values don't get
75057 * assigned on entry. If a binding of the same name already exists, just
75058 * ignore it silently.
75059 */
75060
75061 for (i = 0; i < num_decls; i += 2) {
75062 duk_int_t decl_type;
75063
75064 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
75065 decl_type = duk_to_int(thr, -1);
75066 decl_type = decl_type & 0xff;
75067 duk_pop(thr);
75068
75069 if (decl_type != DUK_DECL_TYPE_VAR) {
75070 continue;
75071 }
75072
75073 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
75074
75075 if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
75076 /* shadowed, ignore */
75077 } else {
75078 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */
75079 h_name = duk_known_hstring(thr, -1);
75080
75081 if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
75082 !comp_ctx->curr_func.is_arguments_shadowed) {
75083 /* E5 Section steps 7-8 */
75084 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
75085 "but appears as a variable declaration -> treat as "
75086 "a no-op for variable declaration purposes"));
75087 duk_pop(thr);
75088 continue;
75089 }
75090
75091 /* XXX: spilling */
75092 if (comp_ctx->curr_func.is_function) {
75093 duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
75094 /* no need to init reg, it will be undefined on entry */
75095 duk_push_int(thr, (duk_int_t) reg_bind);
75096 } else {
75097 duk_dup_top(thr);
75098 rc_name = duk__getconst(comp_ctx);
75099 duk_push_null(thr);
75100
75101 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
75102 DUK_PROPDESC_FLAG_ENUMERABLE;
75103 if (configurable_bindings) {
75104 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
75105 }
75106
75107 duk__emit_a_b_c(comp_ctx,
75108 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
75109 (duk_regconst_t) declvar_flags /*flags*/,
75110 rc_name /*name*/,
75111 0 /*value*/);
75112 }
75113
75114 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
75115 }
75116 }
75117
75118 /*
75119 * Wrap up
75120 */
75121
75122 DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
75123 (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx),
75124 (long) comp_ctx->curr_func.is_arguments_shadowed));
75125
75126 DUK_ASSERT_TOP(thr, entry_top);
75127 return;
75128
75129 error_outofregs:
75130 DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
75131 DUK_WO_NORETURN(return;);
75132
75133 error_argname:
75134 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
75135 DUK_WO_NORETURN(return;);
75136}
75137
75138/*
75139 * Parse a function-body-like expression (FunctionBody or Program
75140 * in E5 grammar) using a two-pass parse. The productions appear
75141 * in the following contexts:
75142 *
75143 * - function expression
75144 * - function statement
75145 * - function declaration
75146 * - getter in object literal
75147 * - setter in object literal
75148 * - global code
75149 * - eval code
75150 * - Function constructor body
75151 *
75152 * This function only parses the statement list of the body; the argument
75153 * list and possible function name must be initialized by the caller.
75154 * For instance, for Function constructor, the argument names are originally
75155 * on the value stack. The parsing of statements ends either at an EOF or
75156 * a closing brace; this is controlled by an input flag.
75157 *
75158 * Note that there are many differences affecting parsing and even code
75159 * generation:
75160 *
75161 * - Global and eval code have an implicit return value generated
75162 * by the last statement; function code does not
75163 *
75164 * - Global code, eval code, and Function constructor body end in
75165 * an EOF, other bodies in a closing brace ('}')
75166 *
75167 * Upon entry, 'curr_tok' is ignored and the function will pull in the
75168 * first token on its own. Upon exit, 'curr_tok' is the terminating
75169 * token (EOF or closing brace).
75170 */
75171
75172DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token) {
75173 duk_compiler_func *func;
75174 duk_hthread *thr;
75175 duk_regconst_t reg_stmt_value = -1;
75176 duk_lexer_point lex_pt;
75177 duk_regconst_t temp_first;
75178 duk_small_int_t compile_round = 1;
75179
75180 DUK_ASSERT(comp_ctx != NULL);
75181
75182 thr = comp_ctx->thr;
75183 DUK_ASSERT(thr != NULL);
75184
75185 func = &comp_ctx->curr_func;
75186 DUK_ASSERT(func != NULL);
75187
75188 DUK__RECURSION_INCREASE(comp_ctx, thr);
75189
75190 duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
75191
75192 /*
75193 * Store lexer position for a later rewind
75194 */
75195
75196 DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
75197
75198 /*
75199 * Program code (global and eval code) has an implicit return value
75200 * from the last statement value (e.g. eval("1; 2+3;") returns 3).
75201 * This is not the case with functions. If implicit statement return
75202 * value is requested, all statements are coerced to a register
75203 * allocated here, and used in the implicit return statement below.
75204 */
75205
75206 /* XXX: this is pointless here because pass 1 is throw-away */
75207 if (implicit_return_value) {
75208 reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
75209
75210 /* If an implicit return value is needed by caller, it must be
75211 * initialized to 'undefined' because we don't know whether any
75212 * non-empty (where "empty" is a continuation type, and different
75213 * from an empty statement) statements will be executed.
75214 *
75215 * However, since 1st pass is a throwaway one, no need to emit
75216 * it here.
75217 */
75218#if 0
75219 duk__emit_bc(comp_ctx,
75220 DUK_OP_LDUNDEF,
75221 0);
75222#endif
75223 }
75224
75225 /*
75226 * First pass.
75227 *
75228 * Gather variable/function declarations needed for second pass.
75229 * Code generated is dummy and discarded.
75230 */
75231
75232 func->in_directive_prologue = 1;
75233 func->in_scanning = 1;
75234 func->may_direct_eval = 0;
75235 func->id_access_arguments = 0;
75236 func->id_access_slow = 0;
75237 func->id_access_slow_own = 0;
75238 func->reg_stmt_value = reg_stmt_value;
75239#if defined(DUK_USE_DEBUGGER_SUPPORT)
75240 func->min_line = DUK_INT_MAX;
75241 func->max_line = 0;
75242#endif
75243
75244 /* duk__parse_stmts() expects curr_tok to be set; parse in "allow
75245 * regexp literal" mode with current strictness.
75246 */
75247 if (expect_token >= 0) {
75248 /* Eating a left curly; regexp mode is allowed by left curly
75249 * based on duk__token_lbp[] automatically.
75250 */
75251 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
75252 duk__update_lineinfo_currtoken(comp_ctx);
75253 duk__advance_expect(comp_ctx, expect_token);
75254 } else {
75255 /* Need to set curr_token.t because lexing regexp mode depends on current
75256 * token type. Zero value causes "allow regexp" mode.
75257 */
75258 comp_ctx->curr_token.t = 0;
75259 duk__advance(comp_ctx);
75260 }
75261
75262 DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
75263 duk__parse_stmts(comp_ctx,
75264 1, /* allow source elements */
75265 expect_eof, /* expect EOF instead of } */
75266 regexp_after); /* regexp after */
75267 DUK_DDD(DUK_DDDPRINT("end 1st pass"));
75268
75269 /*
75270 * Second (and possibly third) pass.
75271 *
75272 * Generate actual code. In most cases the need for shuffle
75273 * registers is detected during pass 1, but in some corner cases
75274 * we'll only detect it during pass 2 and a third pass is then
75275 * needed (see GH-115).
75276 */
75277
75278 for (;;) {
75279 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
75280 compile_round++;
75281
75282 /*
75283 * Rewind lexer.
75284 *
75285 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
75286 * literal" mode with current strictness.
75287 *
75288 * curr_token line number info should be initialized for pass 2 before
75289 * generating prologue, to ensure prologue bytecode gets nice line numbers.
75290 */
75291
75292 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
75293 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
75294 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
75295 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
75296 duk__advance(comp_ctx);
75297
75298 /*
75299 * Reset function state and perform register allocation, which creates
75300 * 'varmap' for second pass. Function prologue for variable declarations,
75301 * binding value initializations etc is emitted as a by-product.
75302 *
75303 * Strict mode restrictions for duplicate and invalid argument
75304 * names are checked here now that we know whether the function
75305 * is actually strict. See: test-dev-strict-mode-boundary.js.
75306 *
75307 * Inner functions are compiled during pass 1 and are not reset.
75308 */
75309
75310 duk__reset_func_for_pass2(comp_ctx);
75311 func->in_directive_prologue = 1;
75312 func->in_scanning = 0;
75313
75314 /* must be able to emit code, alloc consts, etc. */
75315
75316 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
75317 (implicit_return_value ? &reg_stmt_value : NULL));
75318 func->reg_stmt_value = reg_stmt_value;
75319
75320 temp_first = DUK__GETTEMP(comp_ctx);
75321
75322 func->temp_first = temp_first;
75323 func->temp_next = temp_first;
75324 func->stmt_next = 0;
75325 func->label_next = 0;
75326
75327 /* XXX: init or assert catch depth etc -- all values */
75328 func->id_access_arguments = 0;
75329 func->id_access_slow = 0;
75330 func->id_access_slow_own = 0;
75331
75332 /*
75333 * Check function name validity now that we know strictness.
75334 * This only applies to function declarations and expressions,
75335 * not setter/getter name.
75336 *
75337 * See: test-dev-strict-mode-boundary.js
75338 */
75339
75340 if (func->is_function && !func->is_setget && func->h_name != NULL) {
75341 if (func->is_strict) {
75342 if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
75343 DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
75344 goto error_funcname;
75345 }
75346 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
75347 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
75348 goto error_funcname;
75349 }
75350 } else {
75351 if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
75352 !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
75353 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
75354 goto error_funcname;
75355 }
75356 }
75357 }
75358
75359 /*
75360 * Second pass parsing.
75361 */
75362
75363 if (implicit_return_value) {
75364 /* Default implicit return value. */
75365 duk__emit_bc(comp_ctx,
75366 DUK_OP_LDUNDEF,
75367 0);
75368 }
75369
75370 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
75371 duk__parse_stmts(comp_ctx,
75372 1, /* allow source elements */
75373 expect_eof, /* expect EOF instead of } */
75374 regexp_after); /* regexp after */
75375 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
75376
75377 duk__update_lineinfo_currtoken(comp_ctx);
75378
75379 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
75380 /* Shuffle decision not changed. */
75381 break;
75382 }
75383 if (compile_round >= 3) {
75384 /* Should never happen but avoid infinite loop just in case. */
75385 DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
75386 DUK_ERROR_INTERNAL(thr);
75387 DUK_WO_NORETURN(return;);
75388 }
75389 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
75390 }
75391
75392 /*
75393 * Emit a final RETURN.
75394 *
75395 * It would be nice to avoid emitting an unnecessary "return" opcode
75396 * if the current PC is not reachable. However, this cannot be reliably
75397 * detected; even if the previous instruction is an unconditional jump,
75398 * there may be a previous jump which jumps to current PC (which is the
75399 * case for iteration and conditional statements, for instance).
75400 */
75401
75402 /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
75403 * we could avoid the last RETURN if we could ensure there is no way to get here
75404 * (directly or via a jump)
75405 */
75406
75407 DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
75408 if (reg_stmt_value >= 0) {
75409 DUK_ASSERT(DUK__ISREG(reg_stmt_value));
75410 duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/);
75411 } else {
75412 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
75413 }
75414
75415 /*
75416 * Peephole optimize JUMP chains.
75417 */
75418
75419 duk__peephole_optimize_bytecode(comp_ctx);
75420
75421 /*
75422 * comp_ctx->curr_func is now ready to be converted into an actual
75423 * function template.
75424 */
75425
75426 DUK__RECURSION_DECREASE(comp_ctx, thr);
75427 return;
75428
75429 error_funcname:
75430 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
75431 DUK_WO_NORETURN(return;);
75432}
75433
75434/*
75435 * Parse a function-like expression:
75436 *
75437 * - function expression
75438 * - function declaration
75439 * - function statement (non-standard)
75440 * - setter/getter
75441 *
75442 * Adds the function to comp_ctx->curr_func function table and returns the
75443 * function number.
75444 *
75445 * On entry, curr_token points to:
75446 *
75447 * - the token after 'function' for function expression/declaration/statement
75448 * - the token after 'set' or 'get' for setter/getter
75449 */
75450
75451/* Parse formals. */
75452DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
75453 duk_hthread *thr = comp_ctx->thr;
75454 duk_bool_t first = 1;
75455 duk_uarridx_t n;
75456
75457 for (;;) {
75458 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
75459 break;
75460 }
75461
75462 if (first) {
75463 /* no comma */
75464 first = 0;
75465 } else {
75466 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
75467 }
75468
75469 /* Note: when parsing a formal list in non-strict context, e.g.
75470 * "implements" is parsed as an identifier. When the function is
75471 * later detected to be strict, the argument list must be rechecked
75472 * against a larger set of reserved words (that of strict mode).
75473 * This is handled by duk__parse_func_body(). Here we recognize
75474 * whatever tokens are considered reserved in current strictness
75475 * (which is not always enough).
75476 */
75477
75478 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
75479 DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
75480 DUK_WO_NORETURN(return;);
75481 }
75482 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
75483 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
75484 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
75485 (duk_heaphdr *) comp_ctx->curr_token.str1));
75486
75487 /* XXX: append primitive */
75488 duk_push_hstring(thr, comp_ctx->curr_token.str1);
75489 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
75490 duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n);
75491
75492 duk__advance(comp_ctx); /* eat identifier */
75493 }
75494}
75495
75496/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
75497 * correctly set up. Assumes that curr_token is just after 'function' (or
75498 * 'set'/'get' etc).
75499 */
75500DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
75501 duk_hthread *thr = comp_ctx->thr;
75502 duk_token *tok;
75503 duk_bool_t no_advance;
75504
75505 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
75506 DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
75507 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
75508 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
75509 DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0));
75510
75511 duk__update_lineinfo_currtoken(comp_ctx);
75512
75513 /*
75514 * Function name (if any)
75515 *
75516 * We don't check for prohibited names here, because we don't
75517 * yet know whether the function will be strict. Function body
75518 * parsing handles this retroactively.
75519 *
75520 * For function expressions and declarations function name must
75521 * be an Identifer (excludes reserved words). For setter/getter
75522 * it is a PropertyName which allows reserved words and also
75523 * strings and numbers (e.g. "{ get 1() { ... } }").
75524 *
75525 * Function parsing may start either from prev_token or curr_token
75526 * (object literal method definition uses prev_token for example).
75527 * This is dealt with for the initial token.
75528 */
75529
75530 no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN);
75531 if (no_advance) {
75532 tok = &comp_ctx->prev_token;
75533 } else {
75534 tok = &comp_ctx->curr_token;
75535 }
75536
75537 if (flags & DUK__FUNC_FLAG_GETSET) {
75538 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
75539 if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) {
75540 duk_push_hstring(thr, tok->str1); /* keep in valstack */
75541 } else if (tok->t == DUK_TOK_NUMBER) {
75542 duk_push_number(thr, tok->num);
75543 duk_to_string(thr, -1);
75544 } else {
75545 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
75546 DUK_WO_NORETURN(return;);
75547 }
75548 comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
75549 } else {
75550 /* Function name is an Identifier (not IdentifierName), but we get
75551 * the raw name (not recognizing keywords) here and perform the name
75552 * checks only after pass 1.
75553 */
75554 if (tok->t_nores == DUK_TOK_IDENTIFIER) {
75555 duk_push_hstring(thr, tok->str1); /* keep in valstack */
75556 comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */
75557 } else {
75558 /* valstack will be unbalanced, which is OK */
75559 DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0);
75560 DUK_ASSERT(comp_ctx->curr_func.h_name == NULL);
75561 no_advance = 1;
75562 if (flags & DUK__FUNC_FLAG_DECL) {
75563 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
75564 DUK_WO_NORETURN(return;);
75565 }
75566 }
75567 }
75568
75569 DUK_DD(DUK_DDPRINT("function name: %!O",
75570 (duk_heaphdr *) comp_ctx->curr_func.h_name));
75571
75572 if (!no_advance) {
75573 duk__advance(comp_ctx);
75574 }
75575
75576 /*
75577 * Formal argument list
75578 *
75579 * We don't check for prohibited names or for duplicate argument
75580 * names here, becase we don't yet know whether the function will
75581 * be strict. Function body parsing handles this retroactively.
75582 */
75583
75584 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
75585
75586 duk__parse_func_formals(comp_ctx);
75587
75588 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
75589 duk__advance(comp_ctx);
75590
75591 /*
75592 * Parse function body
75593 */
75594
75595 duk__parse_func_body(comp_ctx,
75596 0, /* expect_eof */
75597 0, /* implicit_return_value */
75598 flags & DUK__FUNC_FLAG_DECL, /* regexp_after */
75599 DUK_TOK_LCURLY); /* expect_token */
75600
75601 /*
75602 * Convert duk_compiler_func to a function template and add it
75603 * to the parent function table.
75604 */
75605
75606 duk__convert_to_func_template(comp_ctx); /* -> [ ... func ] */
75607}
75608
75609/* Parse an inner function, adding the function template to the current function's
75610 * function table. Return a function number to be used by the outer function.
75611 *
75612 * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
75613 * compile and register the function normally into the 'funcs' array, also recording
75614 * a lexer point (offset/line) to the closing brace of the function. On the second
75615 * pass, skip the function and return the same 'fnum' as on the first pass by using
75616 * a running counter.
75617 *
75618 * An unfortunate side effect of this is that when parsing the inner function, almost
75619 * nothing is known of the outer function, i.e. the inner function's scope. We don't
75620 * need that information at the moment, but it would allow some optimizations if it
75621 * were used.
75622 */
75623DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
75624 duk_hthread *thr = comp_ctx->thr;
75625 duk_compiler_func old_func;
75626 duk_idx_t entry_top;
75627 duk_int_t fnum;
75628
75629 /*
75630 * On second pass, skip the function.
75631 */
75632
75633 if (!comp_ctx->curr_func.in_scanning) {
75634 duk_lexer_point lex_pt;
75635
75636 fnum = comp_ctx->curr_func.fnum_next++;
75637 duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
75638 lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1);
75639 duk_pop(thr);
75640 duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
75641 lex_pt.line = duk_to_int(thr, -1);
75642 duk_pop(thr);
75643
75644 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
75645 (long) lex_pt.offset, (long) lex_pt.line));
75646
75647 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
75648 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
75649 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
75650 duk__advance(comp_ctx);
75651
75652 /* RegExp is not allowed after a function expression, e.g. in
75653 * (function () {} / 123). A RegExp *is* allowed after a
75654 * function declaration!
75655 */
75656 if (flags & DUK__FUNC_FLAG_DECL) {
75657 comp_ctx->curr_func.allow_regexp_in_adv = 1;
75658 }
75659 duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
75660
75661 return fnum;
75662 }
75663
75664 /*
75665 * On first pass, perform actual parsing. Remember valstack top on entry
75666 * to restore it later, and switch to using a new function in comp_ctx.
75667 */
75668
75669 entry_top = duk_get_top(thr);
75670 DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
75671 (long) entry_top, (long) comp_ctx->curr_token.start_offset));
75672
75673 duk_memcpy(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
75674
75675 duk_memzero(&comp_ctx->curr_func, sizeof(duk_compiler_func));
75676 duk__init_func_valstack_slots(comp_ctx);
75677 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
75678
75679 /* inherit initial strictness from parent */
75680 comp_ctx->curr_func.is_strict = old_func.is_strict;
75681
75682 /* XXX: It might be better to just store the flags into the curr_func
75683 * struct and use them as is without this flag interpretation step
75684 * here.
75685 */
75686 DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
75687 comp_ctx->curr_func.is_function = 1;
75688 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
75689 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
75690 comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0);
75691 comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET |
75692 DUK__FUNC_FLAG_METDEF |
75693 DUK__FUNC_FLAG_DECL)); /* no name binding for: declarations, objlit getset, objlit method def */
75694 comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET |
75695 DUK__FUNC_FLAG_METDEF)); /* not constructable: objlit getset, objlit method def */
75696
75697 /*
75698 * Parse inner function
75699 */
75700
75701 duk__parse_func_like_raw(comp_ctx, flags); /* pushes function template */
75702
75703 /* prev_token.start_offset points to the closing brace here; when skipping
75704 * we're going to reparse the closing brace to ensure semicolon insertion
75705 * etc work as expected.
75706 */
75707 DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
75708 (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
75709 DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
75710
75711 /* XXX: append primitive */
75712 DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
75713 fnum = old_func.fnum_next++;
75714
75715 if (fnum > DUK__MAX_FUNCS) {
75716 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
75717 DUK_WO_NORETURN(return 0;);
75718 }
75719
75720 /* array writes autoincrement length */
75721 (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
75722 duk_push_size_t(thr, comp_ctx->prev_token.start_offset);
75723 (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
75724 duk_push_int(thr, comp_ctx->prev_token.start_line);
75725 (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
75726
75727 /*
75728 * Cleanup: restore original function, restore valstack state.
75729 *
75730 * Function declaration handling needs the function name to be pushed
75731 * on the value stack.
75732 */
75733
75734 if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) {
75735 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
75736 duk_push_hstring(thr, comp_ctx->curr_func.h_name);
75737 duk_replace(thr, entry_top);
75738 duk_set_top(thr, entry_top + 1);
75739 } else {
75740 duk_set_top(thr, entry_top);
75741 }
75742 duk_memcpy((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
75743
75744 return fnum;
75745}
75746
75747/*
75748 * Compile input string into an executable function template without
75749 * arguments.
75750 *
75751 * The string is parsed as the "Program" production of ECMAScript E5.
75752 * Compilation context can be either global code or eval code (see E5
75753 * Sections 14 and 15.1.2.1).
75754 *
75755 * Input stack: [ ... filename ]
75756 * Output stack: [ ... func_template ]
75757 */
75758
75759/* XXX: source code property */
75760
75761DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) {
75762 duk_hstring *h_filename;
75763 duk__compiler_stkstate *comp_stk;
75764 duk_compiler_ctx *comp_ctx;
75765 duk_lexer_point *lex_pt;
75766 duk_compiler_func *func;
75767 duk_idx_t entry_top;
75768 duk_bool_t is_strict;
75769 duk_bool_t is_eval;
75770 duk_bool_t is_funcexpr;
75771 duk_small_uint_t flags;
75772
75773 DUK_ASSERT(thr != NULL);
75774 DUK_ASSERT(udata != NULL);
75775
75776 /*
75777 * Arguments check
75778 */
75779
75780 entry_top = duk_get_top(thr);
75781 DUK_ASSERT(entry_top >= 1);
75782
75783 comp_stk = (duk__compiler_stkstate *) udata;
75784 comp_ctx = &comp_stk->comp_ctx_alloc;
75785 lex_pt = &comp_stk->lex_pt_alloc;
75786 DUK_ASSERT(comp_ctx != NULL);
75787 DUK_ASSERT(lex_pt != NULL);
75788
75789 flags = comp_stk->flags;
75790 is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0);
75791 is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0);
75792 is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0);
75793
75794 h_filename = duk_get_hstring(thr, -1); /* may be undefined */
75795
75796 /*
75797 * Init compiler and lexer contexts
75798 */
75799
75800 func = &comp_ctx->curr_func;
75801#if defined(DUK_USE_EXPLICIT_NULL_INIT)
75802 comp_ctx->thr = NULL;
75803 comp_ctx->h_filename = NULL;
75804 comp_ctx->prev_token.str1 = NULL;
75805 comp_ctx->prev_token.str2 = NULL;
75806 comp_ctx->curr_token.str1 = NULL;
75807 comp_ctx->curr_token.str2 = NULL;
75808#endif
75809
75810 duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS);
75811
75812 duk_push_dynamic_buffer(thr, 0); /* entry_top + 0 */
75813 duk_push_undefined(thr); /* entry_top + 1 */
75814 duk_push_undefined(thr); /* entry_top + 2 */
75815 duk_push_undefined(thr); /* entry_top + 3 */
75816 duk_push_undefined(thr); /* entry_top + 4 */
75817
75818 comp_ctx->thr = thr;
75819 comp_ctx->h_filename = h_filename;
75820 comp_ctx->tok11_idx = entry_top + 1;
75821 comp_ctx->tok12_idx = entry_top + 2;
75822 comp_ctx->tok21_idx = entry_top + 3;
75823 comp_ctx->tok22_idx = entry_top + 4;
75824 comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
75825
75826 /* comp_ctx->lex has been pre-initialized by caller: it has been
75827 * zeroed and input/input_length has been set.
75828 */
75829 comp_ctx->lex.thr = thr;
75830 /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
75831 comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
75832 comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
75833 comp_ctx->lex.buf_idx = entry_top + 0;
75834 comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0);
75835 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
75836 comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
75837
75838 lex_pt->offset = 0;
75839 lex_pt->line = 1;
75840 DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */
75841 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
75842
75843 /*
75844 * Initialize function state for a zero-argument function
75845 */
75846
75847 duk__init_func_valstack_slots(comp_ctx);
75848 DUK_ASSERT(func->num_formals == 0);
75849
75850 if (is_funcexpr) {
75851 /* Name will be filled from function expression, not by caller.
75852 * This case is used by Function constructor and duk_compile()
75853 * API with the DUK_COMPILE_FUNCTION option.
75854 */
75855 DUK_ASSERT(func->h_name == NULL);
75856 } else {
75857 duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL :
75858 DUK_STRIDX_GLOBAL));
75859 func->h_name = duk_get_hstring(thr, -1);
75860 }
75861
75862 /*
75863 * Parse a function body or a function-like expression, depending
75864 * on flags.
75865 */
75866
75867 DUK_ASSERT(func->is_setget == 0);
75868 func->is_strict = (duk_uint8_t) is_strict;
75869 DUK_ASSERT(func->is_notail == 0);
75870
75871 if (is_funcexpr) {
75872 func->is_function = 1;
75873 DUK_ASSERT(func->is_eval == 0);
75874 DUK_ASSERT(func->is_global == 0);
75875 func->is_namebinding = 1;
75876 func->is_constructable = 1;
75877
75878 duk__advance(comp_ctx); /* init 'curr_token' */
75879 duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
75880 (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/);
75881 } else {
75882 DUK_ASSERT(func->is_function == 0);
75883 DUK_ASSERT(is_eval == 0 || is_eval == 1);
75884 func->is_eval = (duk_uint8_t) is_eval;
75885 func->is_global = (duk_uint8_t) !is_eval;
75886 DUK_ASSERT(func->is_namebinding == 0);
75887 DUK_ASSERT(func->is_constructable == 0);
75888
75889 duk__parse_func_body(comp_ctx,
75890 1, /* expect_eof */
75891 1, /* implicit_return_value */
75892 1, /* regexp_after (does not matter) */
75893 -1); /* expect_token */
75894 }
75895
75896 /*
75897 * Convert duk_compiler_func to a function template
75898 */
75899
75900 duk__convert_to_func_template(comp_ctx);
75901
75902 /*
75903 * Wrapping duk_safe_call() will mangle the stack, just return stack top
75904 */
75905
75906 /* [ ... filename (temps) func ] */
75907
75908 return 1;
75909}
75910
75911DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
75912 duk__compiler_stkstate comp_stk;
75913 duk_compiler_ctx *prev_ctx;
75914 duk_ret_t safe_rc;
75915
75916 DUK_ASSERT(thr != NULL);
75917 DUK_ASSERT(src_buffer != NULL);
75918
75919 /* preinitialize lexer state partially */
75920 duk_memzero(&comp_stk, sizeof(comp_stk));
75921 comp_stk.flags = flags;
75922 DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
75923 comp_stk.comp_ctx_alloc.lex.input = src_buffer;
75924 comp_stk.comp_ctx_alloc.lex.input_length = src_length;
75925 comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */
75926
75927 /* [ ... filename ] */
75928
75929 prev_ctx = thr->compile_ctx;
75930 thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
75931 safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
75932 thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
75933
75934 if (safe_rc != DUK_EXEC_SUCCESS) {
75935 DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1)));
75936 (void) duk_throw(thr);
75937 DUK_WO_NORETURN(return;);
75938 }
75939
75940 /* [ ... template ] */
75941}
75942
75943/* automatic undefs */
75944#undef DUK__ALLOCTEMP
75945#undef DUK__ALLOCTEMPS
75946#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
75947#undef DUK__BC_INITIAL_INSTS
75948#undef DUK__BP_ADDITIVE
75949#undef DUK__BP_ASSIGNMENT
75950#undef DUK__BP_BAND
75951#undef DUK__BP_BOR
75952#undef DUK__BP_BXOR
75953#undef DUK__BP_CALL
75954#undef DUK__BP_CLOSING
75955#undef DUK__BP_COMMA
75956#undef DUK__BP_CONDITIONAL
75957#undef DUK__BP_EOF
75958#undef DUK__BP_EQUALITY
75959#undef DUK__BP_EXPONENTIATION
75960#undef DUK__BP_FOR_EXPR
75961#undef DUK__BP_INVALID
75962#undef DUK__BP_LAND
75963#undef DUK__BP_LOR
75964#undef DUK__BP_MEMBER
75965#undef DUK__BP_MULTIPLICATIVE
75966#undef DUK__BP_POSTFIX
75967#undef DUK__BP_RELATIONAL
75968#undef DUK__BP_SHIFT
75969#undef DUK__COMPILE_ENTRY_SLOTS
75970#undef DUK__CONST_MARKER
75971#undef DUK__DUMP_ISPEC
75972#undef DUK__DUMP_IVALUE
75973#undef DUK__EMIT_FLAG_A_IS_SOURCE
75974#undef DUK__EMIT_FLAG_BC_REGCONST
75975#undef DUK__EMIT_FLAG_B_IS_TARGET
75976#undef DUK__EMIT_FLAG_C_IS_TARGET
75977#undef DUK__EMIT_FLAG_NO_SHUFFLE_A
75978#undef DUK__EMIT_FLAG_NO_SHUFFLE_B
75979#undef DUK__EMIT_FLAG_NO_SHUFFLE_C
75980#undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT
75981#undef DUK__EXPR_FLAG_ALLOW_EMPTY
75982#undef DUK__EXPR_FLAG_REJECT_IN
75983#undef DUK__EXPR_FLAG_REQUIRE_INIT
75984#undef DUK__EXPR_RBP_MASK
75985#undef DUK__FUNCTION_BODY_REQUIRE_SLOTS
75986#undef DUK__FUNCTION_INIT_REQUIRE_SLOTS
75987#undef DUK__FUNC_FLAG_DECL
75988#undef DUK__FUNC_FLAG_GETSET
75989#undef DUK__FUNC_FLAG_METDEF
75990#undef DUK__FUNC_FLAG_PUSHNAME_PASS1
75991#undef DUK__FUNC_FLAG_USE_PREVTOKEN
75992#undef DUK__GETCONST_MAX_CONSTS_CHECK
75993#undef DUK__GETTEMP
75994#undef DUK__HAS_TERM
75995#undef DUK__HAS_VAL
75996#undef DUK__ISCONST
75997#undef DUK__ISREG
75998#undef DUK__ISREG_NOTTEMP
75999#undef DUK__ISREG_TEMP
76000#undef DUK__IS_TERMINAL
76001#undef DUK__IVAL_FLAG_ALLOW_CONST
76002#undef DUK__IVAL_FLAG_REQUIRE_SHORT
76003#undef DUK__IVAL_FLAG_REQUIRE_TEMP
76004#undef DUK__MAX_ARRAY_INIT_VALUES
76005#undef DUK__MAX_CONSTS
76006#undef DUK__MAX_FUNCS
76007#undef DUK__MAX_OBJECT_INIT_PAIRS
76008#undef DUK__MAX_TEMPS
76009#undef DUK__MK_LBP
76010#undef DUK__MK_LBP_FLAGS
76011#undef DUK__OBJ_LIT_KEY_GET
76012#undef DUK__OBJ_LIT_KEY_PLAIN
76013#undef DUK__OBJ_LIT_KEY_SET
76014#undef DUK__PARSE_EXPR_SLOTS
76015#undef DUK__PARSE_STATEMENTS_SLOTS
76016#undef DUK__RECURSION_DECREASE
76017#undef DUK__RECURSION_INCREASE
76018#undef DUK__REMOVECONST
76019#undef DUK__SETTEMP
76020#undef DUK__SETTEMP_CHECKMAX
76021#undef DUK__STILL_PROLOGUE
76022#undef DUK__TOKEN_LBP_BP_MASK
76023#undef DUK__TOKEN_LBP_FLAG_NO_REGEXP
76024#undef DUK__TOKEN_LBP_FLAG_TERMINATES
76025#undef DUK__TOKEN_LBP_FLAG_UNUSED
76026#undef DUK__TOKEN_LBP_GET_BP
76027#line 1 "duk_js_executor.c"
76028/*
76029 * ECMAScript bytecode executor.
76030 */
76031
76032/* #include duk_internal.h -> already included */
76033
76034/*
76035 * Local declarations.
76036 */
76037
76038DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act);
76039
76040/*
76041 * Misc helpers.
76042 */
76043
76044/* Replace value stack top to value at 'tv_ptr'. Optimize for
76045 * performance by only applying the net refcount change.
76046 */
76047#define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \
76048 duk_hthread *duk__thr; \
76049 duk_tval *duk__tvsrc; \
76050 duk_tval *duk__tvdst; \
76051 duk_tval duk__tvtmp; \
76052 duk__thr = (thr); \
76053 duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \
76054 duk__tvdst = (tv_ptr); \
76055 DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \
76056 DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \
76057 DUK_TVAL_SET_UNDEFINED(duk__tvsrc); /* value stack init policy */ \
76058 duk__thr->valstack_top = duk__tvsrc; \
76059 DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \
76060 } while (0)
76061
76062/* XXX: candidate of being an internal shared API call */
76063#if 0 /* unused */
76064DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) {
76065 duk_tval *tv_dst;
76066 duk_size_t copy_size;
76067 duk_size_t i;
76068
76069 tv_dst = thr->valstack_top;
76070 copy_size = sizeof(duk_tval) * count;
76071 duk_memcpy((void *) tv_dst, (const void *) tv_src, copy_size);
76072 for (i = 0; i < count; i++) {
76073 DUK_TVAL_INCREF(thr, tv_dst);
76074 tv_dst++;
76075 }
76076 thr->valstack_top = tv_dst;
76077}
76078#endif
76079
76080/*
76081 * Arithmetic, binary, and logical helpers.
76082 *
76083 * Note: there is no opcode for logical AND or logical OR; this is on
76084 * purpose, because the evalution order semantics for them make such
76085 * opcodes pretty pointless: short circuiting means they are most
76086 * comfortably implemented as jumps. However, a logical NOT opcode
76087 * is useful.
76088 *
76089 * Note: careful with duk_tval pointers here: they are potentially
76090 * invalidated by any DECREF and almost any API call. It's still
76091 * preferable to work without making a copy but that's not always
76092 * possible.
76093 */
76094
76095DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
76096 return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2);
76097}
76098
76099#if defined(DUK_USE_ES7_EXP_OPERATOR)
76100DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) {
76101 return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
76102}
76103#endif
76104
76105DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
76106 /*
76107 * Addition operator is different from other arithmetic
76108 * operations in that it also provides string concatenation.
76109 * Hence it is implemented separately.
76110 *
76111 * There is a fast path for number addition. Other cases go
76112 * through potentially multiple coercions as described in the
76113 * E5 specification. It may be possible to reduce the number
76114 * of coercions, but this must be done carefully to preserve
76115 * the exact semantics.
76116 *
76117 * E5 Section 11.6.1.
76118 *
76119 * Custom types also have special behavior implemented here.
76120 */
76121
76122 duk_double_union du;
76123
76124 DUK_ASSERT(thr != NULL);
76125 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
76126 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
76127 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
76128 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
76129
76130 /*
76131 * Fast paths
76132 */
76133
76134#if defined(DUK_USE_FASTINT)
76135 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
76136 duk_int64_t v1, v2, v3;
76137 duk_int32_t v3_hi;
76138 duk_tval *tv_z;
76139
76140 /* Input values are signed 48-bit so we can detect overflow
76141 * reliably from high bits or just a comparison.
76142 */
76143
76144 v1 = DUK_TVAL_GET_FASTINT(tv_x);
76145 v2 = DUK_TVAL_GET_FASTINT(tv_y);
76146 v3 = v1 + v2;
76147 v3_hi = (duk_int32_t) (v3 >> 32);
76148 if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
76149 tv_z = thr->valstack_bottom + idx_z;
76150 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
76151 return;
76152 } else {
76153 /* overflow, fall through */
76154 ;
76155 }
76156 }
76157#endif /* DUK_USE_FASTINT */
76158
76159 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
76160#if !defined(DUK_USE_EXEC_PREFER_SIZE)
76161 duk_tval *tv_z;
76162#endif
76163
76164 du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
76165#if defined(DUK_USE_EXEC_PREFER_SIZE)
76166 duk_push_number(thr, du.d); /* will NaN normalize result */
76167 duk_replace(thr, (duk_idx_t) idx_z);
76168#else /* DUK_USE_EXEC_PREFER_SIZE */
76169 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
76170 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
76171 tv_z = thr->valstack_bottom + idx_z;
76172 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
76173#endif /* DUK_USE_EXEC_PREFER_SIZE */
76174 return;
76175 }
76176
76177 /*
76178 * Slow path: potentially requires function calls for coercion
76179 */
76180
76181 duk_push_tval(thr, tv_x);
76182 duk_push_tval(thr, tv_y);
76183 duk_to_primitive(thr, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
76184 duk_to_primitive(thr, -1, DUK_HINT_NONE);
76185
76186 /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */
76187 if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) {
76188 /* Symbols shouldn't technically be handled here, but should
76189 * go into the default ToNumber() coercion path instead and
76190 * fail there with a TypeError. However, there's a ToString()
76191 * in duk_concat_2() which also fails with TypeError so no
76192 * explicit check is needed.
76193 */
76194 duk_concat_2(thr); /* [... s1 s2] -> [... s1+s2] */
76195 } else {
76196 duk_double_t d1, d2;
76197
76198 d1 = duk_to_number_m2(thr);
76199 d2 = duk_to_number_m1(thr);
76200 DUK_ASSERT(duk_is_number(thr, -2));
76201 DUK_ASSERT(duk_is_number(thr, -1));
76202 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
76203 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
76204
76205 du.d = d1 + d2;
76206 duk_pop_2_unsafe(thr);
76207 duk_push_number(thr, du.d); /* will NaN normalize result */
76208 }
76209 duk_replace(thr, (duk_idx_t) idx_z); /* side effects */
76210}
76211
76212DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
76213 /*
76214 * Arithmetic operations other than '+' have number-only semantics
76215 * and are implemented here. The separate switch-case here means a
76216 * "double dispatch" of the arithmetic opcode, but saves code space.
76217 *
76218 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
76219 */
76220
76221 duk_double_t d1, d2;
76222 duk_double_union du;
76223 duk_small_uint_fast_t opcode_shifted;
76224#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
76225 duk_tval *tv_z;
76226#endif
76227
76228 DUK_ASSERT(thr != NULL);
76229 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
76230 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
76231 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
76232 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
76233
76234 opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
76235
76236#if defined(DUK_USE_FASTINT)
76237 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
76238 duk_int64_t v1, v2, v3;
76239 duk_int32_t v3_hi;
76240
76241 v1 = DUK_TVAL_GET_FASTINT(tv_x);
76242 v2 = DUK_TVAL_GET_FASTINT(tv_y);
76243
76244 switch (opcode_shifted) {
76245 case DUK_OP_SUB >> 2: {
76246 v3 = v1 - v2;
76247 break;
76248 }
76249 case DUK_OP_MUL >> 2: {
76250 /* Must ensure result is 64-bit (no overflow); a
76251 * simple and sufficient fast path is to allow only
76252 * 32-bit inputs. Avoid zero inputs to avoid
76253 * negative zero issues (-1 * 0 = -0, for instance).
76254 */
76255 if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 &&
76256 v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) {
76257 v3 = v1 * v2;
76258 } else {
76259 goto skip_fastint;
76260 }
76261 break;
76262 }
76263 case DUK_OP_DIV >> 2: {
76264 /* Don't allow a zero divisor. Fast path check by
76265 * "verifying" with multiplication. Also avoid zero
76266 * dividend to avoid negative zero issues (0 / -1 = -0
76267 * for instance).
76268 */
76269 if (v1 == 0 || v2 == 0) {
76270 goto skip_fastint;
76271 }
76272 v3 = v1 / v2;
76273 if (v3 * v2 != v1) {
76274 goto skip_fastint;
76275 }
76276 break;
76277 }
76278 case DUK_OP_MOD >> 2: {
76279 /* Don't allow a zero divisor. Restrict both v1 and
76280 * v2 to positive values to avoid compiler specific
76281 * behavior.
76282 */
76283 if (v1 < 1 || v2 < 1) {
76284 goto skip_fastint;
76285 }
76286 v3 = v1 % v2;
76287 DUK_ASSERT(v3 >= 0);
76288 DUK_ASSERT(v3 < v2);
76289 DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
76290 break;
76291 }
76292 default: {
76293 /* Possible with DUK_OP_EXP. */
76294 goto skip_fastint;
76295 }
76296 }
76297
76298 v3_hi = (duk_int32_t) (v3 >> 32);
76299 if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
76300 tv_z = thr->valstack_bottom + idx_z;
76301 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
76302 return;
76303 }
76304 /* fall through if overflow etc */
76305 }
76306 skip_fastint:
76307#endif /* DUK_USE_FASTINT */
76308
76309 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
76310 /* fast path */
76311 d1 = DUK_TVAL_GET_NUMBER(tv_x);
76312 d2 = DUK_TVAL_GET_NUMBER(tv_y);
76313 } else {
76314 duk_push_tval(thr, tv_x);
76315 duk_push_tval(thr, tv_y);
76316 d1 = duk_to_number_m2(thr); /* side effects */
76317 d2 = duk_to_number_m1(thr);
76318 DUK_ASSERT(duk_is_number(thr, -2));
76319 DUK_ASSERT(duk_is_number(thr, -1));
76320 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
76321 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
76322 duk_pop_2_unsafe(thr);
76323 }
76324
76325 switch (opcode_shifted) {
76326 case DUK_OP_SUB >> 2: {
76327 du.d = d1 - d2;
76328 break;
76329 }
76330 case DUK_OP_MUL >> 2: {
76331 du.d = d1 * d2;
76332 break;
76333 }
76334 case DUK_OP_DIV >> 2: {
76335 /* Division-by-zero is undefined behavior, so
76336 * rely on a helper.
76337 */
76338 du.d = duk_double_div(d1, d2);
76339 break;
76340 }
76341 case DUK_OP_MOD >> 2: {
76342 du.d = duk__compute_mod(d1, d2);
76343 break;
76344 }
76345#if defined(DUK_USE_ES7_EXP_OPERATOR)
76346 case DUK_OP_EXP >> 2: {
76347 du.d = duk__compute_exp(d1, d2);
76348 break;
76349 }
76350#endif
76351 default: {
76352 DUK_UNREACHABLE();
76353 du.d = DUK_DOUBLE_NAN; /* should not happen */
76354 break;
76355 }
76356 }
76357
76358#if defined(DUK_USE_EXEC_PREFER_SIZE)
76359 duk_push_number(thr, du.d); /* will NaN normalize result */
76360 duk_replace(thr, (duk_idx_t) idx_z);
76361#else /* DUK_USE_EXEC_PREFER_SIZE */
76362 /* important to use normalized NaN with 8-byte tagged types */
76363 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
76364 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
76365 tv_z = thr->valstack_bottom + idx_z;
76366 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
76367#endif /* DUK_USE_EXEC_PREFER_SIZE */
76368}
76369
76370DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
76371 /*
76372 * Binary bitwise operations use different coercions (ToInt32, ToUint32)
76373 * depending on the operation. We coerce the arguments first using
76374 * ToInt32(), and then cast to an 32-bit value if necessary. Note that
76375 * such casts must be correct even if there is no native 32-bit type
76376 * (e.g., duk_int32_t and duk_uint32_t are 64-bit).
76377 *
76378 * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
76379 */
76380
76381 duk_int32_t i1, i2, i3;
76382 duk_uint32_t u1, u2, u3;
76383#if defined(DUK_USE_FASTINT)
76384 duk_int64_t fi3;
76385#else
76386 duk_double_t d3;
76387#endif
76388 duk_small_uint_fast_t opcode_shifted;
76389#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
76390 duk_tval *tv_z;
76391#endif
76392
76393 DUK_ASSERT(thr != NULL);
76394 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
76395 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
76396 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
76397 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
76398
76399 opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
76400
76401#if defined(DUK_USE_FASTINT)
76402 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
76403 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
76404 i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
76405 }
76406 else
76407#endif /* DUK_USE_FASTINT */
76408 {
76409 duk_push_tval(thr, tv_x);
76410 duk_push_tval(thr, tv_y);
76411 i1 = duk_to_int32(thr, -2);
76412 i2 = duk_to_int32(thr, -1);
76413 duk_pop_2_unsafe(thr);
76414 }
76415
76416 switch (opcode_shifted) {
76417 case DUK_OP_BAND >> 2: {
76418 i3 = i1 & i2;
76419 break;
76420 }
76421 case DUK_OP_BOR >> 2: {
76422 i3 = i1 | i2;
76423 break;
76424 }
76425 case DUK_OP_BXOR >> 2: {
76426 i3 = i1 ^ i2;
76427 break;
76428 }
76429 case DUK_OP_BASL >> 2: {
76430 /* Signed shift, named "arithmetic" (asl) because the result
76431 * is signed, e.g. 4294967295 << 1 -> -2. Note that result
76432 * must be masked.
76433 */
76434
76435 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
76436 i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */
76437 i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
76438 break;
76439 }
76440 case DUK_OP_BASR >> 2: {
76441 /* signed shift */
76442
76443 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
76444 i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
76445 break;
76446 }
76447 case DUK_OP_BLSR >> 2: {
76448 /* unsigned shift */
76449
76450 u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
76451 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
76452
76453 /* special result value handling */
76454 u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
76455#if defined(DUK_USE_FASTINT)
76456 fi3 = (duk_int64_t) u3;
76457 goto fastint_result_set;
76458#else
76459 d3 = (duk_double_t) u3;
76460 goto result_set;
76461#endif
76462 }
76463 default: {
76464 DUK_UNREACHABLE();
76465 i3 = 0; /* should not happen */
76466 break;
76467 }
76468 }
76469
76470#if defined(DUK_USE_FASTINT)
76471 /* Result is always fastint compatible. */
76472 /* XXX: Set 32-bit result (but must then handle signed and
76473 * unsigned results separately).
76474 */
76475 fi3 = (duk_int64_t) i3;
76476
76477 fastint_result_set:
76478 tv_z = thr->valstack_bottom + idx_z;
76479 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
76480#else /* DUK_USE_FASTINT */
76481 d3 = (duk_double_t) i3;
76482
76483 result_set:
76484 DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
76485 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
76486
76487#if defined(DUK_USE_EXEC_PREFER_SIZE)
76488 duk_push_number(thr, d3); /* would NaN normalize result, but unnecessary */
76489 duk_replace(thr, (duk_idx_t) idx_z);
76490#else /* DUK_USE_EXEC_PREFER_SIZE */
76491 tv_z = thr->valstack_bottom + idx_z;
76492 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
76493#endif /* DUK_USE_EXEC_PREFER_SIZE */
76494#endif /* DUK_USE_FASTINT */
76495}
76496
76497/* In-place unary operation. */
76498DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst, duk_small_uint_fast_t opcode) {
76499 /*
76500 * Arithmetic operations other than '+' have number-only semantics
76501 * and are implemented here. The separate switch-case here means a
76502 * "double dispatch" of the arithmetic opcode, but saves code space.
76503 *
76504 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
76505 */
76506
76507 duk_tval *tv;
76508 duk_double_t d1;
76509 duk_double_union du;
76510
76511 DUK_ASSERT(thr != NULL);
76512 DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP);
76513 DUK_ASSERT_DISABLE(idx_src >= 0);
76514 DUK_ASSERT_DISABLE(idx_dst >= 0);
76515
76516 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
76517
76518#if defined(DUK_USE_FASTINT)
76519 if (DUK_TVAL_IS_FASTINT(tv)) {
76520 duk_int64_t v1, v2;
76521
76522 v1 = DUK_TVAL_GET_FASTINT(tv);
76523 if (opcode == DUK_OP_UNM) {
76524 /* The smallest fastint is no longer 48-bit when
76525 * negated. Positive zero becames negative zero
76526 * (cannot be represented) when negated.
76527 */
76528 if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
76529 v2 = -v1;
76530 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76531 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
76532 return;
76533 }
76534 } else {
76535 /* ToNumber() for a fastint is a no-op. */
76536 DUK_ASSERT(opcode == DUK_OP_UNP);
76537 v2 = v1;
76538 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76539 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
76540 return;
76541 }
76542 /* fall through if overflow etc */
76543 }
76544#endif /* DUK_USE_FASTINT */
76545
76546 if (DUK_TVAL_IS_NUMBER(tv)) {
76547 d1 = DUK_TVAL_GET_NUMBER(tv);
76548 } else {
76549 d1 = duk_to_number_tval(thr, tv); /* side effects */
76550 }
76551
76552 if (opcode == DUK_OP_UNP) {
76553 /* ToNumber() for a double is a no-op, but unary plus is
76554 * used to force a fastint check so do that here.
76555 */
76556 du.d = d1;
76557 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
76558#if defined(DUK_USE_FASTINT)
76559 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76560 DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */
76561 return;
76562#endif
76563 } else {
76564 DUK_ASSERT(opcode == DUK_OP_UNM);
76565 du.d = -d1;
76566 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
76567 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
76568 }
76569
76570 /* XXX: size optimize: push+replace? */
76571 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76572 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d);
76573}
76574
76575DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
76576 /*
76577 * E5 Section 11.4.8
76578 */
76579
76580 duk_tval *tv;
76581 duk_int32_t i1, i2;
76582
76583 DUK_ASSERT(thr != NULL);
76584 DUK_ASSERT_DISABLE(idx_src >= 0);
76585 DUK_ASSERT_DISABLE(idx_dst >= 0);
76586 DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
76587 DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
76588
76589 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
76590
76591#if defined(DUK_USE_FASTINT)
76592 if (DUK_TVAL_IS_FASTINT(tv)) {
76593 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv);
76594 }
76595 else
76596#endif /* DUK_USE_FASTINT */
76597 {
76598 duk_push_tval(thr, tv);
76599 i1 = duk_to_int32(thr, -1); /* side effects */
76600 duk_pop_unsafe(thr);
76601 }
76602
76603 /* Result is always fastint compatible. */
76604 i2 = ~i1;
76605 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76606 DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */
76607}
76608
76609DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
76610 /*
76611 * E5 Section 11.4.9
76612 */
76613
76614 duk_tval *tv;
76615 duk_bool_t res;
76616
76617 DUK_ASSERT(thr != NULL);
76618 DUK_ASSERT_DISABLE(idx_src >= 0);
76619 DUK_ASSERT_DISABLE(idx_dst >= 0);
76620 DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
76621 DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
76622
76623 /* ToBoolean() does not require any operations with side effects so
76624 * we can do it efficiently. For footprint it would be better to use
76625 * duk_js_toboolean() and then push+replace to the result slot.
76626 */
76627 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
76628 res = duk_js_toboolean(tv); /* does not modify 'tv' */
76629 DUK_ASSERT(res == 0 || res == 1);
76630 res ^= 1;
76631 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
76632 /* XXX: size optimize: push+replace? */
76633 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */
76634}
76635
76636/* XXX: size optimized variant */
76637DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) {
76638 duk_double_t x, y, z;
76639
76640 /* Two lowest bits of opcode are used to distinguish
76641 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
76642 */
76643 DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
76644 DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
76645 DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
76646 DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
76647
76648#if defined(DUK_USE_FASTINT)
76649 if (DUK_TVAL_IS_FASTINT(tv_src)) {
76650 duk_int64_t x_fi, y_fi, z_fi;
76651 x_fi = DUK_TVAL_GET_FASTINT(tv_src);
76652 if (op & 0x01) {
76653 if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) {
76654 goto skip_fastint;
76655 }
76656 y_fi = x_fi - 1;
76657 } else {
76658 if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) {
76659 goto skip_fastint;
76660 }
76661 y_fi = x_fi + 1;
76662 }
76663
76664 DUK_TVAL_SET_FASTINT(tv_src, y_fi); /* no need for refcount update */
76665
76666 z_fi = (op & 0x02) ? x_fi : y_fi;
76667 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi); /* side effects */
76668 return;
76669 }
76670 skip_fastint:
76671#endif
76672 if (DUK_TVAL_IS_NUMBER(tv_src)) {
76673 /* Fast path for the case where the register
76674 * is a number (e.g. loop counter).
76675 */
76676
76677 x = DUK_TVAL_GET_NUMBER(tv_src);
76678 if (op & 0x01) {
76679 y = x - 1.0;
76680 } else {
76681 y = x + 1.0;
76682 }
76683
76684 DUK_TVAL_SET_NUMBER(tv_src, y); /* no need for refcount update */
76685 } else {
76686 /* Preserve duk_tval pointer(s) across a potential valstack
76687 * resize by converting them into offsets temporarily.
76688 */
76689 duk_idx_t bc;
76690 duk_size_t off_dst;
76691
76692 off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom);
76693 bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */
76694 tv_src = NULL; /* no longer referenced */
76695
76696 x = duk_to_number(thr, bc);
76697 if (op & 0x01) {
76698 y = x - 1.0;
76699 } else {
76700 y = x + 1.0;
76701 }
76702
76703 duk_push_number(thr, y);
76704 duk_replace(thr, bc);
76705
76706 tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst);
76707 }
76708
76709 z = (op & 0x02) ? x : y;
76710 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */
76711}
76712
76713DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_small_uint_t is_strict) {
76714 duk_activation *act;
76715 duk_double_t x, y;
76716 duk_hstring *name;
76717
76718 /* XXX: The pre/post inc/dec for an identifier lookup is
76719 * missing the important fast path where the identifier
76720 * has a storage location e.g. in a scope object so that
76721 * it can be updated in-place. In particular, the case
76722 * where the identifier has a storage location AND the
76723 * previous value is a number should be optimized because
76724 * it's side effect free.
76725 */
76726
76727 /* Two lowest bits of opcode are used to distinguish
76728 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
76729 */
76730 DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
76731 DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
76732 DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
76733 DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
76734
76735 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id));
76736 name = DUK_TVAL_GET_STRING(tv_id);
76737 DUK_ASSERT(name != NULL);
76738 act = thr->callstack_curr;
76739 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */
76740
76741 /* XXX: Fastint fast path would be useful here. Also fastints
76742 * now lose their fastint status in current handling which is
76743 * not intuitive.
76744 */
76745
76746 x = duk_to_number_m2(thr);
76747 if (op & 0x01) {
76748 y = x - 1.0;
76749 } else {
76750 y = x + 1.0;
76751 }
76752
76753 /* [... x this] */
76754
76755 if (op & 0x02) {
76756 duk_push_number(thr, y); /* -> [ ... x this y ] */
76757 DUK_ASSERT(act == thr->callstack_curr);
76758 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
76759 duk_pop_2_unsafe(thr); /* -> [ ... x ] */
76760 } else {
76761 duk_pop_2_unsafe(thr); /* -> [ ... ] */
76762 duk_push_number(thr, y); /* -> [ ... y ] */
76763 DUK_ASSERT(act == thr->callstack_curr);
76764 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
76765 }
76766
76767#if defined(DUK_USE_EXEC_PREFER_SIZE)
76768 duk_replace(thr, (duk_idx_t) idx_dst);
76769#else /* DUK_USE_EXEC_PREFER_SIZE */
76770 DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst));
76771#endif /* DUK_USE_EXEC_PREFER_SIZE */
76772}
76773
76774/*
76775 * Longjmp and other control flow transfer for the bytecode executor.
76776 *
76777 * The longjmp handler can handle all longjmp types: error, yield, and
76778 * resume (pseudotypes are never actually thrown).
76779 *
76780 * Error policy for longjmp: should not ordinarily throw errors; if errors
76781 * occur (e.g. due to out-of-memory) they bubble outwards rather than being
76782 * handled recursively.
76783 */
76784
76785#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */
76786#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */
76787
76788#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */
76789#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */
76790
76791/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
76792 * top are combined into one pass.
76793 */
76794
76795/* Reconfigure value stack for return to an ECMAScript function at
76796 * callstack top (caller unwinds).
76797 */
76798DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) {
76799 duk_activation *act;
76800 duk_hcompfunc *h_func;
76801 duk_idx_t clamp_top;
76802
76803 DUK_ASSERT(thr != NULL);
76804 act = thr->callstack_curr;
76805 DUK_ASSERT(act != NULL);
76806 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
76807 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
76808
76809 /* Clamp so that values at 'clamp_top' and above are wiped and won't
76810 * retain reachable garbage. Then extend to 'nregs' because we're
76811 * returning to an ECMAScript function.
76812 */
76813
76814 h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
76815
76816 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
76817 DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff);
76818 clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval)); /* +1 = one retval */
76819 duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
76820
76821 DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
76822 thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
76823
76824 /* XXX: a best effort shrink check would be OK here */
76825}
76826
76827/* Reconfigure value stack for an ECMAScript catcher. Use topmost catcher
76828 * in 'act'.
76829 */
76830DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) {
76831 duk_catcher *cat;
76832 duk_hcompfunc *h_func;
76833 duk_size_t idx_bottom;
76834 duk_idx_t clamp_top;
76835
76836 DUK_ASSERT(thr != NULL);
76837 DUK_ASSERT(act != NULL);
76838 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
76839 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
76840 cat = act->cat;
76841 DUK_ASSERT(cat != NULL);
76842
76843 h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
76844
76845 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
76846 idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack);
76847 DUK_ASSERT(cat->idx_base >= idx_bottom);
76848 clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
76849 duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
76850
76851 DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
76852 thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
76853
76854 /* XXX: a best effort shrink check would be OK here */
76855}
76856
76857/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type.
76858 * No side effects.
76859 */
76860DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
76861 duk_tval *tv1;
76862
76863 DUK_ASSERT(thr != NULL);
76864 DUK_ASSERT(tv_val_unstable != NULL);
76865
76866 tv1 = thr->valstack + cat->idx_base;
76867 DUK_ASSERT(tv1 < thr->valstack_top);
76868 DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable);
76869
76870 tv1++;
76871 DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1);
76872 DUK_ASSERT(tv1 < thr->valstack_top);
76873 DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type);
76874}
76875
76876DUK_LOCAL void duk__handle_catch_part1(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type, volatile duk_bool_t *out_delayed_catch_setup) {
76877 duk_activation *act;
76878 duk_catcher *cat;
76879
76880 DUK_ASSERT(thr != NULL);
76881 DUK_ASSERT(tv_val_unstable != NULL);
76882
76883 act = thr->callstack_curr;
76884 DUK_ASSERT(act != NULL);
76885 DUK_DD(DUK_DDPRINT("handle catch, part 1; act=%!A, cat=%!C", act, act->cat));
76886
76887 DUK_ASSERT(act->cat != NULL);
76888 DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
76889
76890 /* The part1/part2 split could also be made here at the very top
76891 * of catch handling. Value stack would be reconfigured inside
76892 * part2's protection. Value stack reconfiguration should be free
76893 * of allocs, however.
76894 */
76895
76896 duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
76897
76898 DUK_ASSERT(thr->callstack_top >= 1);
76899 DUK_ASSERT(thr->callstack_curr != NULL);
76900 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
76901 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
76902
76903 DUK_ASSERT(thr->callstack_top >= 1);
76904 DUK_ASSERT(act == thr->callstack_curr);
76905 DUK_ASSERT(act != NULL);
76906 duk__reconfig_valstack_ecma_catcher(thr, act);
76907
76908 DUK_ASSERT(thr->callstack_top >= 1);
76909 DUK_ASSERT(act == thr->callstack_curr);
76910 DUK_ASSERT(act != NULL);
76911 cat = act->cat;
76912 DUK_ASSERT(cat != NULL);
76913
76914 act->curr_pc = cat->pc_base + 0; /* +0 = catch */
76915
76916 /*
76917 * If the catch block has an automatic catch variable binding,
76918 * we need to create a lexical environment for it which requires
76919 * allocations. Move out of "error handling state" before the
76920 * allocations to avoid e.g. out-of-memory errors (leading to
76921 * GH-2022 or similar).
76922 */
76923
76924 if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) {
76925 DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding, handle in part 2"));
76926 *out_delayed_catch_setup = 1;
76927 } else {
76928 DUK_DDD(DUK_DDDPRINT("catcher has no catch binding"));
76929 }
76930
76931 DUK_CAT_CLEAR_CATCH_ENABLED(cat);
76932}
76933
76934DUK_LOCAL void duk__handle_catch_part2(duk_hthread *thr) {
76935 duk_activation *act;
76936 duk_catcher *cat;
76937 duk_hdecenv *new_env;
76938
76939 DUK_ASSERT(thr != NULL);
76940
76941 act = thr->callstack_curr;
76942 DUK_ASSERT(act != NULL);
76943 DUK_DD(DUK_DDPRINT("handle catch, part 2; act=%!A, cat=%!C", act, act->cat));
76944
76945 DUK_ASSERT(act->cat != NULL);
76946 cat = act->cat;
76947 DUK_ASSERT(cat != NULL);
76948 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
76949 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
76950 DUK_ASSERT(thr->valstack + cat->idx_base < thr->valstack_top);
76951
76952 /*
76953 * Create lexical environment for the catch clause, containing
76954 * a binding for the caught value.
76955 *
76956 * The binding is mutable (= writable) but not deletable.
76957 * Step 4 for the catch production in E5 Section 12.14;
76958 * no value is given for CreateMutableBinding 'D' argument,
76959 * which implies the binding is not deletable.
76960 */
76961
76962 if (act->lex_env == NULL) {
76963 DUK_ASSERT(act->var_env == NULL);
76964 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
76965
76966 duk_js_init_activation_environment_records_delayed(thr, act);
76967 DUK_ASSERT(act == thr->callstack_curr);
76968 DUK_ASSERT(act != NULL);
76969 }
76970 DUK_ASSERT(act->lex_env != NULL);
76971 DUK_ASSERT(act->var_env != NULL);
76972 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
76973
76974 new_env = duk_hdecenv_alloc(thr,
76975 DUK_HOBJECT_FLAG_EXTENSIBLE |
76976 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
76977 DUK_ASSERT(new_env != NULL);
76978 duk_push_hobject(thr, (duk_hobject *) new_env);
76979 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
76980 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
76981
76982 /* Note: currently the catch binding is handled without a register
76983 * binding because we don't support dynamic register bindings (they
76984 * must be fixed for an entire function). So, there is no need to
76985 * record regbases etc.
76986 */
76987
76988 /* [ ...env ] */
76989
76990 DUK_ASSERT(cat->h_varname != NULL);
76991 duk_push_hstring(thr, cat->h_varname);
76992 DUK_ASSERT(thr->valstack + cat->idx_base < thr->valstack_top);
76993 duk_push_tval(thr, thr->valstack + cat->idx_base);
76994 duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
76995
76996 /* [ ... env ] */
76997
76998 DUK_ASSERT(act == thr->callstack_curr);
76999 DUK_ASSERT(act != NULL);
77000 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env);
77001 act->lex_env = (duk_hobject *) new_env;
77002 DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */
77003 /* Net refcount change to act->lex_env is 0: incref for new_env's
77004 * prototype, decref for act->lex_env overwrite.
77005 */
77006
77007 DUK_CAT_SET_LEXENV_ACTIVE(cat);
77008
77009 duk_pop_unsafe(thr);
77010
77011 DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
77012}
77013
77014DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
77015 duk_activation *act;
77016 duk_catcher *cat;
77017
77018 DUK_ASSERT(thr != NULL);
77019 DUK_ASSERT(tv_val_unstable != NULL);
77020
77021 act = thr->callstack_curr;
77022 DUK_ASSERT(act != NULL);
77023 DUK_ASSERT(act->cat != NULL);
77024 DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
77025
77026 duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
77027
77028 DUK_ASSERT(thr->callstack_top >= 1);
77029 DUK_ASSERT(thr->callstack_curr != NULL);
77030 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
77031 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
77032
77033 DUK_ASSERT(thr->callstack_top >= 1);
77034 DUK_ASSERT(act == thr->callstack_curr);
77035 DUK_ASSERT(act != NULL);
77036 duk__reconfig_valstack_ecma_catcher(thr, act);
77037
77038 DUK_ASSERT(thr->callstack_top >= 1);
77039 DUK_ASSERT(act == thr->callstack_curr);
77040 DUK_ASSERT(act != NULL);
77041 cat = act->cat;
77042 DUK_ASSERT(cat != NULL);
77043
77044 act->curr_pc = cat->pc_base + 1; /* +1 = finally */
77045
77046 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
77047}
77048
77049DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) {
77050 duk_activation *act;
77051 duk_catcher *cat;
77052
77053 DUK_ASSERT(thr != NULL);
77054
77055 DUK_ASSERT(thr->callstack_top >= 1);
77056 act = thr->callstack_curr;
77057 DUK_ASSERT(act != NULL);
77058 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
77059 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
77060
77061 /* +0 = break, +1 = continue */
77062 cat = act->cat;
77063 DUK_ASSERT(cat != NULL);
77064 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
77065
77066 act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
77067
77068 /* valstack should not need changes */
77069#if defined(DUK_USE_ASSERTIONS)
77070 DUK_ASSERT(thr->callstack_top >= 1);
77071 DUK_ASSERT(act == thr->callstack_curr);
77072 DUK_ASSERT(act != NULL);
77073 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
77074 (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs);
77075#endif
77076}
77077
77078/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
77079 * when a RETURN opcode terminates a thread and yields to the resumer.
77080 * Caller unwinds so that top of callstack is the activation we return to.
77081 */
77082#if defined(DUK_USE_COROUTINE_SUPPORT)
77083DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) {
77084 duk_activation *act_resumer;
77085 duk_tval *tv1;
77086
77087 DUK_ASSERT(thr != NULL);
77088 DUK_ASSERT(resumer != NULL);
77089 DUK_ASSERT(tv_val_unstable != NULL);
77090 act_resumer = resumer->callstack_curr;
77091 DUK_ASSERT(act_resumer != NULL);
77092 DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL);
77093 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ECMAScript func */
77094
77095 tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */
77096 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */
77097
77098 duk__reconfig_valstack_ecma_return(resumer);
77099
77100 /* caller must change active thread, and set thr->resumer to NULL */
77101}
77102#endif /* DUK_USE_COROUTINE_SUPPORT */
77103
77104DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act, volatile duk_bool_t *out_delayed_catch_setup) {
77105 duk_small_uint_t retval = DUK__LONGJMP_RESTART;
77106
77107 DUK_ASSERT(thr != NULL);
77108 DUK_ASSERT(entry_act != NULL);
77109
77110 /* 'thr' is the current thread, as no-one resumes except us and we
77111 * switch 'thr' in that case.
77112 */
77113 DUK_ASSERT(thr == thr->heap->curr_thread);
77114
77115 /*
77116 * (Re)try handling the longjmp.
77117 *
77118 * A longjmp handler may convert the longjmp to a different type and
77119 * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto,
77120 * the following must be updated:
77121 * - the heap 'lj' state
77122 * - 'thr' must reflect the "throwing" thread
77123 */
77124
77125 check_longjmp:
77126
77127 DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld, top=%ld",
77128 (long) thr->heap->lj.type,
77129 (duk_tval *) &thr->heap->lj.value1,
77130 (duk_tval *) &thr->heap->lj.value2,
77131 (long) thr->heap->lj.iserror,
77132 (long) duk_get_top(thr)));
77133
77134 switch (thr->heap->lj.type) {
77135
77136#if defined(DUK_USE_COROUTINE_SUPPORT)
77137 case DUK_LJ_TYPE_RESUME: {
77138 /*
77139 * Note: lj.value1 is 'value', lj.value2 is 'resumee'.
77140 * This differs from YIELD.
77141 */
77142
77143 duk_tval *tv;
77144 duk_tval *tv2;
77145 duk_hthread *resumee;
77146
77147 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
77148
77149 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
77150 DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */
77151 DUK_ASSERT(thr->callstack_curr != NULL);
77152 DUK_ASSERT(thr->callstack_curr->parent != NULL);
77153 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
77154 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
77155 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume);
77156
77157 tv = &thr->heap->lj.value2; /* resumee */
77158 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
77159 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
77160 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
77161 resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
77162
77163 DUK_ASSERT(resumee != NULL);
77164 DUK_ASSERT(resumee->resumer == NULL);
77165 DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
77166 resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */
77167 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
77168 resumee->callstack_top >= 2); /* YIELDED: ECMAScript activation + Duktape.Thread.yield() activation */
77169 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
77170 (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL &&
77171 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) &&
77172 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield));
77173 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
77174 resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
77175
77176 if (thr->heap->lj.iserror) {
77177 /*
77178 * Throw the error in the resumed thread's context; the
77179 * error value is pushed onto the resumee valstack.
77180 *
77181 * Note: the callstack of the target may empty in this case
77182 * too (i.e. the target thread has never been resumed). The
77183 * value stack will contain the initial function in that case,
77184 * which we simply ignore.
77185 */
77186
77187 DUK_ASSERT(resumee->resumer == NULL);
77188 resumee->resumer = thr;
77189 DUK_HTHREAD_INCREF(thr, thr);
77190 resumee->state = DUK_HTHREAD_STATE_RUNNING;
77191 thr->state = DUK_HTHREAD_STATE_RESUMED;
77192 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
77193 thr = resumee;
77194
77195 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
77196
77197 /* thr->heap->lj.value1 is already the value to throw */
77198 /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
77199
77200 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
77201
77202 DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
77203 goto check_longjmp;
77204 } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
77205 /* Unwind previous Duktape.Thread.yield() call. The
77206 * activation remaining must always be an ECMAScript
77207 * call now (yield() accepts calls from ECMAScript
77208 * only).
77209 */
77210 duk_activation *act_resumee;
77211
77212 DUK_ASSERT(resumee->callstack_top >= 2);
77213 act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */
77214 DUK_ASSERT(act_resumee != NULL);
77215 act_resumee = act_resumee->parent; /* ECMAScript call site for yield() */
77216 DUK_ASSERT(act_resumee != NULL);
77217
77218 tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */
77219 DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
77220 tv2 = &thr->heap->lj.value1;
77221 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ /* XXX: avoid side effects */
77222
77223 duk_hthread_activation_unwind_norz(resumee); /* unwind to 'yield' caller */
77224 /* no need to unwind catch stack */
77225
77226 duk__reconfig_valstack_ecma_return(resumee);
77227
77228 DUK_ASSERT(resumee->resumer == NULL);
77229 resumee->resumer = thr;
77230 DUK_HTHREAD_INCREF(thr, thr);
77231 resumee->state = DUK_HTHREAD_STATE_RUNNING;
77232 thr->state = DUK_HTHREAD_STATE_RESUMED;
77233 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
77234#if 0
77235 thr = resumee; /* not needed, as we exit right away */
77236#endif
77237 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
77238 retval = DUK__LONGJMP_RESTART;
77239 goto wipe_and_return;
77240 } else {
77241 /* Initial resume call. */
77242 duk_small_uint_t call_flags;
77243 duk_int_t setup_rc;
77244
77245 /* resumee: [... initial_func] (currently actually: [initial_func]) */
77246
77247 duk_push_undefined(resumee);
77248 tv = &thr->heap->lj.value1;
77249 duk_push_tval(resumee, tv);
77250
77251 /* resumee: [... initial_func undefined(= this) resume_value ] */
77252
77253 call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA; /* not tailcall, ecma-to-ecma (assumed to succeed) */
77254
77255 setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags);
77256 if (setup_rc == 0) {
77257 /* This shouldn't happen; Duktape.Thread.resume()
77258 * should make sure of that. If it does happen
77259 * this internal error will propagate out of the
77260 * executor which can be quite misleading.
77261 */
77262 DUK_ERROR_INTERNAL(thr);
77263 DUK_WO_NORETURN(return 0;);
77264 }
77265
77266 DUK_ASSERT(resumee->resumer == NULL);
77267 resumee->resumer = thr;
77268 DUK_HTHREAD_INCREF(thr, thr);
77269 resumee->state = DUK_HTHREAD_STATE_RUNNING;
77270 thr->state = DUK_HTHREAD_STATE_RESUMED;
77271 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
77272#if 0
77273 thr = resumee; /* not needed, as we exit right away */
77274#endif
77275 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
77276 retval = DUK__LONGJMP_RESTART;
77277 goto wipe_and_return;
77278 }
77279 DUK_UNREACHABLE();
77280 break; /* never here */
77281 }
77282
77283 case DUK_LJ_TYPE_YIELD: {
77284 /*
77285 * Currently only allowed only if yielding thread has only
77286 * ECMAScript activations (except for the Duktape.Thread.yield()
77287 * call at the callstack top) and none of them constructor
77288 * calls.
77289 *
77290 * This excludes the 'entry' thread which will always have
77291 * a preventcount > 0.
77292 */
77293
77294 duk_hthread *resumer;
77295
77296 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
77297
77298#if 0 /* entry_thread not available for assert */
77299 DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
77300#endif
77301 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
77302 DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.yield() activation */
77303 DUK_ASSERT(thr->callstack_curr != NULL);
77304 DUK_ASSERT(thr->callstack_curr->parent != NULL);
77305 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
77306 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
77307 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield);
77308 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL &&
77309 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an ECMAScript function */
77310
77311 resumer = thr->resumer;
77312
77313 DUK_ASSERT(resumer != NULL);
77314 DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
77315 DUK_ASSERT(resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */
77316 DUK_ASSERT(resumer->callstack_curr != NULL);
77317 DUK_ASSERT(resumer->callstack_curr->parent != NULL);
77318 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL &&
77319 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) &&
77320 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume);
77321 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL &&
77322 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an ECMAScript function */
77323
77324 if (thr->heap->lj.iserror) {
77325 thr->state = DUK_HTHREAD_STATE_YIELDED;
77326 thr->resumer = NULL;
77327 DUK_HTHREAD_DECREF_NORZ(thr, resumer);
77328 resumer->state = DUK_HTHREAD_STATE_RUNNING;
77329 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
77330 thr = resumer;
77331
77332 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
77333 /* lj.value1 is already set */
77334 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
77335
77336 DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
77337 goto check_longjmp;
77338 } else {
77339 /* When handling the yield, the last reference to
77340 * 'thr' may disappear.
77341 */
77342
77343 DUK_GC_TORTURE(resumer->heap);
77344 duk_hthread_activation_unwind_norz(resumer);
77345 DUK_GC_TORTURE(resumer->heap);
77346 thr->state = DUK_HTHREAD_STATE_YIELDED;
77347 thr->resumer = NULL;
77348 DUK_HTHREAD_DECREF_NORZ(thr, resumer);
77349 resumer->state = DUK_HTHREAD_STATE_RUNNING;
77350 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
77351 duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
77352 thr = resumer;
77353 DUK_GC_TORTURE(resumer->heap);
77354
77355 DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
77356 retval = DUK__LONGJMP_RESTART;
77357 goto wipe_and_return;
77358 }
77359 DUK_UNREACHABLE();
77360 break; /* never here */
77361 }
77362#endif /* DUK_USE_COROUTINE_SUPPORT */
77363
77364 case DUK_LJ_TYPE_THROW: {
77365 /*
77366 * Three possible outcomes:
77367 * * A try or finally catcher is found => resume there.
77368 * (or)
77369 * * The error propagates to the bytecode executor entry
77370 * level (and we're in the entry thread) => rethrow
77371 * with a new longjmp(), after restoring the previous
77372 * catchpoint.
77373 * * The error is not caught in the current thread, so
77374 * the thread finishes with an error. This works like
77375 * a yielded error, except that the thread is finished
77376 * and can no longer be resumed. (There is always a
77377 * resumer in this case.)
77378 *
77379 * Note: until we hit the entry level, there can only be
77380 * ECMAScript activations.
77381 */
77382
77383 duk_activation *act;
77384 duk_catcher *cat;
77385 duk_hthread *resumer;
77386
77387 for (;;) {
77388 act = thr->callstack_curr;
77389 if (act == NULL) {
77390 break;
77391 }
77392
77393 for (;;) {
77394 cat = act->cat;
77395 if (cat == NULL) {
77396 break;
77397 }
77398
77399 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
77400 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
77401
77402 DUK_DDD(DUK_DDDPRINT("before catch part 1: thr=%p, act=%p, cat=%p",
77403 (void *) thr, (void *) act, (void *) act->cat));
77404 duk__handle_catch_part1(thr,
77405 &thr->heap->lj.value1,
77406 DUK_LJ_TYPE_THROW,
77407 out_delayed_catch_setup);
77408
77409 DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
77410 retval = DUK__LONGJMP_RESTART;
77411 goto wipe_and_return;
77412 }
77413
77414 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
77415 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
77416 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
77417
77418 duk__handle_finally(thr,
77419 &thr->heap->lj.value1,
77420 DUK_LJ_TYPE_THROW);
77421
77422 DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
77423 retval = DUK__LONGJMP_RESTART;
77424 goto wipe_and_return;
77425 }
77426
77427 duk_hthread_catcher_unwind_norz(thr, act);
77428 }
77429
77430 if (act == entry_act) {
77431 /* Not caught by anything before entry level; rethrow and let the
77432 * final catcher finish unwinding (esp. value stack).
77433 */
77434 DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
77435 retval = DUK__LONGJMP_RETHROW;
77436 goto just_return;
77437 }
77438
77439 duk_hthread_activation_unwind_norz(thr);
77440 }
77441
77442 DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
77443
77444 /* Not caught by current thread, thread terminates (yield error to resumer);
77445 * note that this may cause a cascade if the resumer terminates with an uncaught
77446 * exception etc (this is OK, but needs careful testing).
77447 */
77448
77449 DUK_ASSERT(thr->resumer != NULL);
77450 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */
77451 DUK_ASSERT(thr->resumer->callstack_curr != NULL);
77452 DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
77453 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
77454 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */
77455
77456 resumer = thr->resumer;
77457
77458 /* reset longjmp */
77459
77460 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */
77461 /* lj.value1 already set */
77462
77463 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
77464 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
77465
77466 thr->resumer = NULL;
77467 DUK_HTHREAD_DECREF_NORZ(thr, resumer);
77468 resumer->state = DUK_HTHREAD_STATE_RUNNING;
77469 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
77470 thr = resumer;
77471 goto check_longjmp;
77472 }
77473
77474 case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */
77475 case DUK_LJ_TYPE_CONTINUE:
77476 case DUK_LJ_TYPE_RETURN:
77477 case DUK_LJ_TYPE_NORMAL:
77478 default: {
77479 /* should never happen, but be robust */
77480 DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
77481 goto convert_to_internal_error;
77482 }
77483
77484 } /* end switch */
77485
77486 DUK_UNREACHABLE();
77487
77488 wipe_and_return:
77489 DUK_DD(DUK_DDPRINT("handling longjmp done, wipe-and-return, top=%ld",
77490 (long) duk_get_top(thr)));
77491 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
77492 thr->heap->lj.iserror = 0;
77493
77494 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
77495 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
77496
77497 DUK_GC_TORTURE(thr->heap);
77498
77499 just_return:
77500 return retval;
77501
77502 convert_to_internal_error:
77503 /* This could also be thrown internally (set the error, goto check_longjmp),
77504 * but it's better for internal errors to bubble outwards so that we won't
77505 * infinite loop in this catchpoint.
77506 */
77507 DUK_ERROR_INTERNAL(thr);
77508 DUK_WO_NORETURN(return 0;);
77509}
77510
77511/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE
77512 * handling because it has a measurable performance impact in ordinary
77513 * environments and an extreme impact in Emscripten (GH-342).
77514 */
77515DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr,
77516 duk_uint_t label_id,
77517 duk_small_uint_t lj_type) {
77518 duk_activation *act;
77519 duk_catcher *cat;
77520
77521 DUK_ASSERT(thr != NULL);
77522
77523 /* Find a matching label catcher or 'finally' catcher in
77524 * the same function, unwinding catchers as we go.
77525 *
77526 * A label catcher must always exist and will match unless
77527 * a 'finally' captures the break/continue first. It is the
77528 * compiler's responsibility to ensure that labels are used
77529 * correctly.
77530 */
77531
77532 act = thr->callstack_curr;
77533 DUK_ASSERT(act != NULL);
77534
77535 for (;;) {
77536 cat = act->cat;
77537 if (cat == NULL) {
77538 break;
77539 }
77540
77541 DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld",
77542 (void *) cat,
77543 (long) DUK_CAT_GET_TYPE(cat),
77544 (long) DUK_CAT_GET_LABEL(cat)));
77545
77546 /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */
77547
77548 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
77549 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
77550 duk_tval tv_tmp;
77551
77552 DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id);
77553 duk__handle_finally(thr, &tv_tmp, lj_type);
77554
77555 DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
77556 return;
77557 }
77558 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
77559 (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
77560 duk__handle_label(thr, lj_type);
77561
77562 DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
77563 return;
77564 }
77565
77566 duk_hthread_catcher_unwind_norz(thr, act);
77567 }
77568
77569 /* Should never happen, but be robust. */
77570 DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
77571 DUK_ERROR_INTERNAL(thr);
77572 DUK_WO_NORETURN(return;);
77573}
77574
77575/* Handle a RETURN opcode. Avoid using longjmp() for return handling because
77576 * it has a measurable performance impact in ordinary environments and an extreme
77577 * impact in Emscripten (GH-342). Return value is on value stack top.
77578 */
77579DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) {
77580 duk_tval *tv1;
77581 duk_tval *tv2;
77582#if defined(DUK_USE_COROUTINE_SUPPORT)
77583 duk_hthread *resumer;
77584#endif
77585 duk_activation *act;
77586 duk_catcher *cat;
77587
77588 /* We can directly access value stack here. */
77589
77590 DUK_ASSERT(thr != NULL);
77591 DUK_ASSERT(entry_act != NULL);
77592 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
77593 tv1 = thr->valstack_top - 1;
77594 DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */
77595
77596 /*
77597 * Four possible outcomes:
77598 *
77599 * 1. A 'finally' in the same function catches the 'return'.
77600 * It may continue to propagate when 'finally' is finished,
77601 * or it may be neutralized by 'finally' (both handled by
77602 * ENDFIN).
77603 *
77604 * 2. The return happens at the entry level of the bytecode
77605 * executor, so return from the executor (in C stack).
77606 *
77607 * 3. There is a calling (ECMAScript) activation in the call
77608 * stack => return to it, in the same executor instance.
77609 *
77610 * 4. There is no calling activation, and the thread is
77611 * terminated. There is always a resumer in this case,
77612 * which gets the return value similarly to a 'yield'
77613 * (except that the current thread can no longer be
77614 * resumed).
77615 */
77616
77617 DUK_ASSERT(thr != NULL);
77618 DUK_ASSERT(thr->callstack_top >= 1);
77619
77620 act = thr->callstack_curr;
77621 DUK_ASSERT(act != NULL);
77622
77623 for (;;) {
77624 cat = act->cat;
77625 if (cat == NULL) {
77626 break;
77627 }
77628
77629 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
77630 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
77631 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
77632 duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
77633
77634 DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
77635 return DUK__RETHAND_RESTART;
77636 }
77637
77638 duk_hthread_catcher_unwind_norz(thr, act);
77639 }
77640
77641 if (act == entry_act) {
77642 /* Return to the bytecode executor caller who will unwind stacks
77643 * and handle constructor post-processing.
77644 * Return value is already on the stack top: [ ... retval ].
77645 */
77646
77647 DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
77648 return DUK__RETHAND_FINISHED;
77649 }
77650
77651 if (thr->callstack_top >= 2) {
77652 /* There is a caller; it MUST be an ECMAScript caller (otherwise it would
77653 * match entry_act check).
77654 */
77655 DUK_DDD(DUK_DDDPRINT("return to ECMAScript caller, retval_byteoff=%ld, lj_value1=%!T",
77656 (long) (thr->callstack_curr->parent->retval_byteoff),
77657 (duk_tval *) &thr->heap->lj.value1));
77658
77659 DUK_ASSERT(thr->callstack_curr != NULL);
77660 DUK_ASSERT(thr->callstack_curr->parent != NULL);
77661 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ECMAScript */
77662
77663#if defined(DUK_USE_ES6_PROXY)
77664 if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) {
77665 duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY); /* side effects */
77666 }
77667#else
77668 if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) {
77669 duk_call_construct_postprocess(thr, 0); /* side effects */
77670 }
77671#endif
77672
77673 tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff);
77674 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
77675 tv2 = thr->valstack_top - 1;
77676 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
77677
77678 /* Catch stack unwind happens inline in callstack unwind. */
77679 duk_hthread_activation_unwind_norz(thr);
77680
77681 duk__reconfig_valstack_ecma_return(thr);
77682
77683 DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
77684 return DUK__RETHAND_RESTART;
77685 }
77686
77687#if defined(DUK_USE_COROUTINE_SUPPORT)
77688 DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
77689
77690 DUK_ASSERT(thr->resumer != NULL);
77691 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */
77692 DUK_ASSERT(thr->resumer->callstack_curr != NULL);
77693 DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
77694 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL &&
77695 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
77696 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
77697 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
77698 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */
77699 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
77700 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
77701
77702 resumer = thr->resumer;
77703
77704 /* Share yield longjmp handler.
77705 *
77706 * This sequence of steps is a bit fragile (see GH-1845):
77707 * - We need the return value from 'thr' (resumed thread) value stack.
77708 * The termination unwinds its value stack, losing the value.
77709 * - We need a refcounted reference for 'thr', which may only exist
77710 * in the caller value stack. We can't unwind or reconfigure the
77711 * caller's value stack without potentially freeing 'thr'.
77712 *
77713 * Current approach is to capture the 'thr' return value and store
77714 * a reference to 'thr' in the caller value stack temporarily. This
77715 * keeps 'thr' reachable until final yield/return handling which
77716 * removes the references atomatically.
77717 */
77718
77719 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
77720 duk_hthread_activation_unwind_norz(resumer); /* May remove last reference to 'thr', but is NORZ. */
77721 duk_push_tval(resumer, thr->valstack_top - 1); /* Capture return value, side effect free. */
77722 duk_push_hthread(resumer, thr); /* Make 'thr' reachable again, before side effects. */
77723
77724 duk_hthread_terminate(thr); /* Updates thread state, minimizes its allocations. */
77725 thr->resumer = NULL;
77726 DUK_HTHREAD_DECREF(thr, resumer);
77727 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
77728
77729 resumer->state = DUK_HTHREAD_STATE_RUNNING;
77730 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
77731
77732 DUK_ASSERT(resumer->valstack_top - 2 >= resumer->valstack_bottom);
77733 duk__handle_yield(thr, resumer, resumer->valstack_top - 2);
77734 thr = NULL; /* 'thr' invalidated by call */
77735
77736#if 0
77737 thr = resumer; /* not needed */
77738#endif
77739
77740 DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
77741 return DUK__RETHAND_RESTART;
77742#else
77743 /* Without coroutine support this case should never happen. */
77744 DUK_ERROR_INTERNAL(thr);
77745 DUK_WO_NORETURN(return 0;);
77746#endif
77747}
77748
77749/*
77750 * Executor interrupt handling
77751 *
77752 * The handler is called whenever the interrupt countdown reaches zero
77753 * (or below). The handler must perform whatever checks are activated,
77754 * e.g. check for cumulative step count to impose an execution step
77755 * limit or check for breakpoints or other debugger interaction.
77756 *
77757 * When the actions are done, the handler must reinit the interrupt
77758 * init and counter values. The 'init' value must indicate how many
77759 * bytecode instructions are executed before the next interrupt. The
77760 * counter must interface with the bytecode executor loop. Concretely,
77761 * the new init value is normally one higher than the new counter value.
77762 * For instance, to execute exactly one bytecode instruction the init
77763 * value is set to 1 and the counter to 0. If an error is thrown by the
77764 * interrupt handler, the counters are set to the same value (e.g. both
77765 * to 0 to cause an interrupt when the next bytecode instruction is about
77766 * to be executed after error handling).
77767 *
77768 * Maintaining the init/counter value properly is important for accurate
77769 * behavior. For instance, executor step limit needs a cumulative step
77770 * count which is simply computed as a sum of 'init' values. This must
77771 * work accurately even when single stepping.
77772 */
77773
77774#if defined(DUK_USE_INTERRUPT_COUNTER)
77775
77776#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */
77777#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */
77778
77779#if defined(DUK_USE_DEBUGGER_SUPPORT)
77780DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
77781 duk_activation *act;
77782 duk_breakpoint *bp;
77783 duk_breakpoint **bp_active;
77784 duk_uint_fast32_t line = 0;
77785 duk_bool_t process_messages;
77786 duk_bool_t processed_messages = 0;
77787
77788 DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
77789
77790 act = thr->callstack_curr;
77791 DUK_ASSERT(act != NULL);
77792
77793 /* It might seem that replacing 'thr->heap' with just 'heap' below
77794 * might be a good idea, but it increases code size slightly
77795 * (probably due to unnecessary spilling) at least on x64.
77796 */
77797
77798 /*
77799 * Single opcode step check
77800 */
77801
77802 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) {
77803 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step"));
77804 duk_debug_set_paused(thr->heap);
77805 }
77806
77807 /*
77808 * Breakpoint and step state checks
77809 */
77810
77811 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
77812 (thr->heap->dbg_pause_act == thr->callstack_curr)) {
77813 line = duk_debug_curr_line(thr);
77814
77815 if (act->prev_line != line) {
77816 /* Stepped? Step out is handled by callstack unwind. */
77817 if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
77818 (thr->heap->dbg_pause_act == thr->callstack_curr) &&
77819 (line != thr->heap->dbg_pause_startline)) {
77820 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld",
77821 (long) line));
77822 duk_debug_set_paused(thr->heap);
77823 }
77824
77825 /* Check for breakpoints only on line transition.
77826 * Breakpoint is triggered when we enter the target
77827 * line from a different line, and the previous line
77828 * was within the same function.
77829 *
77830 * This condition is tricky: the condition used to be
77831 * that transition to -or across- the breakpoint line
77832 * triggered the breakpoint. This seems intuitively
77833 * better because it handles breakpoints on lines with
77834 * no emitted opcodes; but this leads to the issue
77835 * described in: https://github.com/svaarala/duktape/issues/263.
77836 */
77837 bp_active = thr->heap->dbg_breakpoints_active;
77838 for (;;) {
77839 bp = *bp_active++;
77840 if (bp == NULL) {
77841 break;
77842 }
77843
77844 DUK_ASSERT(bp->filename != NULL);
77845 if (act->prev_line != bp->line && line == bp->line) {
77846 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld",
77847 (duk_heaphdr *) bp->filename, (long) bp->line));
77848 duk_debug_set_paused(thr->heap);
77849 }
77850 }
77851 } else {
77852 ;
77853 }
77854
77855 act->prev_line = (duk_uint32_t) line;
77856 }
77857
77858 /*
77859 * Rate limit check for sending status update or peeking into
77860 * the debug transport. Both can be expensive operations that
77861 * we don't want to do on every opcode.
77862 *
77863 * Making sure the interval remains reasonable on a wide variety
77864 * of targets and bytecode is difficult without a timestamp, so
77865 * we use a Date-provided timestamp for the rate limit check.
77866 * But since it's also expensive to get a timestamp, a bytecode
77867 * counter is used to rate limit getting timestamps.
77868 */
77869
77870 process_messages = 0;
77871 if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) {
77872 /* Enter message processing loop for sending Status notifys and
77873 * to finish a pending detach.
77874 */
77875 process_messages = 1;
77876 }
77877
77878 /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
77879 DUK_ASSERT(thr->interrupt_init >= 0);
77880 thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init;
77881 if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
77882 /* Overflow of the execution counter is fine and doesn't break
77883 * anything here.
77884 */
77885
77886 duk_double_t now, diff_last;
77887
77888 thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
77889 now = duk_time_get_monotonic_time(thr);
77890
77891 diff_last = now - thr->heap->dbg_last_time;
77892 if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
77893 /* Monotonic time should not experience time jumps,
77894 * but the provider may be missing and we're actually
77895 * using ECMAScript time. So, tolerate negative values
77896 * so that a time jump works reasonably.
77897 *
77898 * Same interval is now used for status sending and
77899 * peeking.
77900 */
77901
77902 thr->heap->dbg_last_time = now;
77903 thr->heap->dbg_state_dirty = 1;
77904 process_messages = 1;
77905 }
77906 }
77907
77908 /*
77909 * Process messages and send status if necessary.
77910 *
77911 * If we're paused, we'll block for new messages. If we're not
77912 * paused, we'll process anything we can peek but won't block
77913 * for more. Detach (and re-attach) handling is all localized
77914 * to duk_debug_process_messages() too.
77915 *
77916 * Debugger writes outside the message loop may cause debugger
77917 * detach1 phase to run, after which dbg_read_cb == NULL and
77918 * dbg_detaching != 0. The message loop will finish the detach
77919 * by running detach2 phase, so enter the message loop also when
77920 * detaching.
77921 */
77922
77923 if (process_messages) {
77924 DUK_ASSERT(thr->heap->dbg_processing == 0);
77925 processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
77926 DUK_ASSERT(thr->heap->dbg_processing == 0);
77927 }
77928
77929 /* Continue checked execution if there are breakpoints or we're stepping.
77930 * Also use checked execution if paused flag is active - it shouldn't be
77931 * because the debug message loop shouldn't terminate if it was. Step out
77932 * is handled by callstack unwind and doesn't need checked execution.
77933 * Note that debugger may have detached due to error or explicit request
77934 * above, so we must recheck attach status.
77935 */
77936
77937 if (duk_debug_is_attached(thr->heap)) {
77938 DUK_ASSERT(act == thr->callstack_curr);
77939 DUK_ASSERT(act != NULL);
77940 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
77941 (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) ||
77942 ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
77943 thr->heap->dbg_pause_act == thr->callstack_curr) ||
77944 DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
77945 *out_immediate = 1;
77946 }
77947
77948 /* If we processed any debug messages breakpoints may have
77949 * changed; restart execution to re-check active breakpoints.
77950 */
77951 if (processed_messages) {
77952 DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
77953 *out_interrupt_retval = DUK__INT_RESTART;
77954 } else {
77955 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) {
77956 /* Set 'pause after one opcode' active only when we're
77957 * actually just about to execute code.
77958 */
77959 thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE;
77960 }
77961 }
77962 } else {
77963 DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
77964 }
77965}
77966#endif /* DUK_USE_DEBUGGER_SUPPORT */
77967
77968DUK_LOCAL DUK_EXEC_NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
77969 duk_int_t ctr;
77970 duk_activation *act;
77971 duk_hcompfunc *fun;
77972 duk_bool_t immediate = 0;
77973 duk_small_uint_t retval;
77974
77975 DUK_ASSERT(thr != NULL);
77976 DUK_ASSERT(thr->heap != NULL);
77977 DUK_ASSERT(thr->callstack_top > 0);
77978
77979#if defined(DUK_USE_DEBUG)
77980 thr->heap->inst_count_interrupt += thr->interrupt_init;
77981 DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
77982 "instruction counts: executor=%ld, interrupt=%ld",
77983 (long) thr->interrupt_counter, (long) thr->interrupt_init,
77984 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
77985#endif
77986
77987 retval = DUK__INT_NOACTION;
77988 ctr = DUK_HTHREAD_INTCTR_DEFAULT;
77989
77990 /*
77991 * Avoid nested calls. Concretely this happens during debugging, e.g.
77992 * when we eval() an expression.
77993 *
77994 * Also don't interrupt if we're currently doing debug processing
77995 * (which can be initiated outside the bytecode executor) as this
77996 * may cause the debugger to be called recursively. Check required
77997 * for correct operation of throw intercept and other "exotic" halting
77998 * scenarios.
77999 */
78000
78001#if defined(DUK_USE_DEBUGGER_SUPPORT)
78002 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
78003#else
78004 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
78005#endif
78006 DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
78007
78008 /* Set a high interrupt counter; the original executor
78009 * interrupt invocation will rewrite before exiting.
78010 */
78011 thr->interrupt_init = ctr;
78012 thr->interrupt_counter = ctr - 1;
78013 return DUK__INT_NOACTION;
78014 }
78015 DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
78016
78017 act = thr->callstack_curr;
78018 DUK_ASSERT(act != NULL);
78019
78020 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
78021 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun));
78022
78023 DUK_UNREF(fun);
78024
78025#if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
78026 /*
78027 * Execution timeout check
78028 */
78029
78030 if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
78031 /* Keep throwing an error whenever we get here. The unusual values
78032 * are set this way because no instruction is ever executed, we just
78033 * throw an error until all try/catch/finally and other catchpoints
78034 * have been exhausted. Duktape/C code gets control at each protected
78035 * call but whenever it enters back into Duktape the RangeError gets
78036 * raised. User exec timeout check must consistently indicate a timeout
78037 * until we've fully bubbled out of Duktape.
78038 */
78039 DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
78040 thr->interrupt_init = 0;
78041 thr->interrupt_counter = 0;
78042 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
78043 DUK_ERROR_RANGE(thr, "execution timeout");
78044 DUK_WO_NORETURN(return 0;);
78045 }
78046#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */
78047
78048#if defined(DUK_USE_DEBUGGER_SUPPORT)
78049 if (!thr->heap->dbg_processing &&
78050 (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
78051 /* Avoid recursive re-entry; enter when we're attached or
78052 * detaching (to finish off the pending detach).
78053 */
78054 duk__interrupt_handle_debugger(thr, &immediate, &retval);
78055 DUK_ASSERT(act == thr->callstack_curr);
78056 }
78057#endif /* DUK_USE_DEBUGGER_SUPPORT */
78058
78059 /*
78060 * Update the interrupt counter
78061 */
78062
78063 if (immediate) {
78064 /* Cause an interrupt after executing one instruction. */
78065 ctr = 1;
78066 }
78067
78068 /* The counter value is one less than the init value: init value should
78069 * indicate how many instructions are executed before interrupt. To
78070 * execute 1 instruction (after interrupt handler return), counter must
78071 * be 0.
78072 */
78073 DUK_ASSERT(ctr >= 1);
78074 thr->interrupt_init = ctr;
78075 thr->interrupt_counter = ctr - 1;
78076 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
78077
78078 return retval;
78079}
78080#endif /* DUK_USE_INTERRUPT_COUNTER */
78081
78082/*
78083 * Debugger handling for executor restart
78084 *
78085 * Check for breakpoints, stepping, etc, and figure out if we should execute
78086 * in checked or normal mode. Note that we can't do this when an activation
78087 * is created, because breakpoint status (and stepping status) may change
78088 * later, so we must recheck every time we're executing an activation.
78089 * This primitive should be side effect free to avoid changes during check.
78090 */
78091
78092#if defined(DUK_USE_DEBUGGER_SUPPORT)
78093DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) {
78094 duk_heap *heap;
78095 duk_tval *tv_tmp;
78096 duk_hstring *filename;
78097 duk_small_uint_t bp_idx;
78098 duk_breakpoint **bp_active;
78099
78100 DUK_ASSERT(thr != NULL);
78101 DUK_ASSERT(act != NULL);
78102 DUK_ASSERT(fun != NULL);
78103
78104 heap = thr->heap;
78105 bp_active = heap->dbg_breakpoints_active;
78106 act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
78107
78108 tv_tmp = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) fun, DUK_STRIDX_FILE_NAME);
78109 if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
78110 filename = DUK_TVAL_GET_STRING(tv_tmp);
78111
78112 /* Figure out all active breakpoints. A breakpoint is
78113 * considered active if the current function's fileName
78114 * matches the breakpoint's fileName, AND there is no
78115 * inner function that has matching line numbers
78116 * (otherwise a breakpoint would be triggered both
78117 * inside and outside of the inner function which would
78118 * be confusing). Example:
78119 *
78120 * function foo() {
78121 * print('foo');
78122 * function bar() { <-. breakpoints in these
78123 * print('bar'); | lines should not affect
78124 * } <-' foo() execution
78125 * bar();
78126 * }
78127 *
78128 * We need a few things that are only available when
78129 * debugger support is enabled: (1) a line range for
78130 * each function, and (2) access to the function
78131 * template to access the inner functions (and their
78132 * line ranges).
78133 *
78134 * It's important to have a narrow match for active
78135 * breakpoints so that we don't enter checked execution
78136 * when that's not necessary. For instance, if we're
78137 * running inside a certain function and there's
78138 * breakpoint outside in (after the call site), we
78139 * don't want to slow down execution of the function.
78140 */
78141
78142 for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
78143 duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
78144 duk_hobject **funcs, **funcs_end;
78145 duk_hcompfunc *inner_fun;
78146 duk_bool_t bp_match;
78147
78148 if (bp->filename == filename &&
78149 bp->line >= fun->start_line && bp->line <= fun->end_line) {
78150 bp_match = 1;
78151 DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
78152 "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
78153 DUK_HSTRING_GET_DATA(bp->filename),
78154 (long) bp->line,
78155 DUK_HSTRING_GET_DATA(filename),
78156 (long) bp->line,
78157 (long) fun->start_line,
78158 (long) fun->end_line));
78159
78160 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun);
78161 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun);
78162 while (funcs != funcs_end) {
78163 inner_fun = (duk_hcompfunc *) *funcs;
78164 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun));
78165 if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
78166 DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
78167 bp_match = 0;
78168 break;
78169 }
78170 funcs++;
78171 }
78172
78173 if (bp_match) {
78174 /* No need to check for size of bp_active list,
78175 * it's always larger than maximum number of
78176 * breakpoints.
78177 */
78178 act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
78179 *bp_active = heap->dbg_breakpoints + bp_idx;
78180 bp_active++;
78181 }
78182 }
78183 }
78184 }
78185
78186 *bp_active = NULL; /* terminate */
78187
78188 DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
78189
78190 /* Force pause if we were doing "step into" in another activation. */
78191 if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) &&
78192 thr->heap->dbg_pause_act != thr->callstack_curr) {
78193 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry"));
78194 duk_debug_set_paused(thr->heap);
78195 }
78196
78197 /* Force interrupt right away if we're paused or in "checked mode".
78198 * Step out is handled by callstack unwind.
78199 */
78200 if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
78201 DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ||
78202 ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
78203 thr->heap->dbg_pause_act == thr->callstack_curr)) {
78204 /* We'll need to interrupt early so recompute the init
78205 * counter to reflect the number of bytecode instructions
78206 * executed so that step counts for e.g. debugger rate
78207 * limiting are accurate.
78208 */
78209 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
78210 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
78211 thr->interrupt_counter = 0;
78212 }
78213}
78214#endif /* DUK_USE_DEBUGGER_SUPPORT */
78215
78216/*
78217 * Opcode handlers for opcodes with a lot of code and which are relatively
78218 * rare; NOINLINE to reduce amount of code in main bytecode dispatcher.
78219 */
78220
78221DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) {
78222 duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET);
78223 duk_uint_fast_t idx;
78224 duk_uint_t defprop_flags;
78225
78226 /* A -> object register (acts as a source)
78227 * BC -> BC+0 contains key, BC+1 closure (value)
78228 */
78229
78230 /* INITSET/INITGET are only used to initialize object literal keys.
78231 * There may be a previous propery in ES2015 because duplicate property
78232 * names are allowed.
78233 */
78234
78235 /* This could be made more optimal by accessing internals directly. */
78236
78237 idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
78238 duk_dup(thr, (duk_idx_t) (idx + 0)); /* key */
78239 duk_dup(thr, (duk_idx_t) (idx + 1)); /* getter/setter */
78240 if (is_set) {
78241 defprop_flags = DUK_DEFPROP_HAVE_SETTER |
78242 DUK_DEFPROP_FORCE |
78243 DUK_DEFPROP_SET_ENUMERABLE |
78244 DUK_DEFPROP_SET_CONFIGURABLE;
78245 } else {
78246 defprop_flags = DUK_DEFPROP_HAVE_GETTER |
78247 DUK_DEFPROP_FORCE |
78248 DUK_DEFPROP_SET_ENUMERABLE |
78249 DUK_DEFPROP_SET_CONFIGURABLE;
78250 }
78251 duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
78252}
78253
78254DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) {
78255 duk_activation *act;
78256 duk_catcher *cat;
78257 duk_tval *tv1;
78258 duk_small_uint_fast_t a;
78259 duk_small_uint_fast_t bc;
78260
78261 /* A -> flags
78262 * BC -> reg_catch; base register for two registers used both during
78263 * trycatch setup and when catch is triggered
78264 *
78265 * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
78266 * reg_catch + 0: catch binding variable name (string).
78267 * Automatic declarative environment is established for
78268 * the duration of the 'catch' clause.
78269 *
78270 * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
78271 * reg_catch + 0: with 'target value', which is coerced to
78272 * an object and then used as a bindind object for an
78273 * environment record. The binding is initialized here, for
78274 * the 'try' clause.
78275 *
78276 * Note that a TRYCATCH generated for a 'with' statement has no
78277 * catch or finally parts.
78278 */
78279
78280 /* XXX: TRYCATCH handling should be reworked to avoid creating
78281 * an explicit scope unless it is actually needed (e.g. function
78282 * instances or eval is executed inside the catch block). This
78283 * rework is not trivial because the compiler doesn't have an
78284 * intermediate representation. When the rework is done, the
78285 * opcode format can also be made more straightforward.
78286 */
78287
78288 /* XXX: side effect handling is quite awkward here */
78289
78290 DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
78291 "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
78292 (long) DUK_DEC_BC(ins),
78293 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
78294 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
78295 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
78296 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
78297 (unsigned long) DUK_DEC_A(ins)));
78298
78299 a = DUK_DEC_A(ins);
78300 bc = DUK_DEC_BC(ins);
78301
78302 /* Registers 'bc' and 'bc + 1' are written in longjmp handling
78303 * and if their previous values (which are temporaries) become
78304 * unreachable -and- have a finalizer, there'll be a function
78305 * call during error handling which is not supported now (GH-287).
78306 * Ensure that both 'bc' and 'bc + 1' have primitive values to
78307 * guarantee no finalizer calls in error handling. Scrubbing also
78308 * ensures finalizers for the previous values run here rather than
78309 * later. Error handling related values are also written to 'bc'
78310 * and 'bc + 1' but those values never become unreachable during
78311 * error handling, so there's no side effect problem even if the
78312 * error value has a finalizer.
78313 */
78314 duk_dup(thr, (duk_idx_t) bc); /* Stabilize value. */
78315 duk_to_undefined(thr, (duk_idx_t) bc);
78316 duk_to_undefined(thr, (duk_idx_t) (bc + 1));
78317
78318 /* Allocate catcher and populate it. Doesn't have to
78319 * be fully atomic, but the catcher must be in a
78320 * consistent state if side effects (such as finalizer
78321 * calls) occur.
78322 */
78323
78324 cat = duk_hthread_catcher_alloc(thr);
78325 DUK_ASSERT(cat != NULL);
78326
78327 cat->flags = DUK_CAT_TYPE_TCF;
78328 cat->h_varname = NULL;
78329 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
78330 cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
78331
78332 act = thr->callstack_curr;
78333 DUK_ASSERT(act != NULL);
78334 cat->parent = act->cat;
78335 act->cat = cat;
78336
78337 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
78338 cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
78339 }
78340 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
78341 cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
78342 }
78343 if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
78344 DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
78345 cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
78346 tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
78347 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
78348
78349 /* borrowed reference; although 'tv1' comes from a register,
78350 * its value was loaded using LDCONST so the constant will
78351 * also exist and be reachable.
78352 */
78353 cat->h_varname = DUK_TVAL_GET_STRING(tv1);
78354 } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
78355 duk_hobjenv *env;
78356 duk_hobject *target;
78357
78358 /* Delayed env initialization for activation (if needed). */
78359 DUK_ASSERT(thr->callstack_top >= 1);
78360 DUK_ASSERT(act == thr->callstack_curr);
78361 DUK_ASSERT(act != NULL);
78362 if (act->lex_env == NULL) {
78363 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
78364 DUK_ASSERT(act->var_env == NULL);
78365
78366 duk_js_init_activation_environment_records_delayed(thr, act);
78367 DUK_ASSERT(act == thr->callstack_curr);
78368 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
78369 }
78370 DUK_ASSERT(act->lex_env != NULL);
78371 DUK_ASSERT(act->var_env != NULL);
78372
78373 /* Coerce 'with' target. */
78374 target = duk_to_hobject(thr, -1);
78375 DUK_ASSERT(target != NULL);
78376
78377 /* Create an object environment; it is not pushed
78378 * so avoid side effects very carefully until it is
78379 * referenced.
78380 */
78381 env = duk_hobjenv_alloc(thr,
78382 DUK_HOBJECT_FLAG_EXTENSIBLE |
78383 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
78384 DUK_ASSERT(env != NULL);
78385 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
78386 env->target = target; /* always provideThis=true */
78387 DUK_HOBJECT_INCREF(thr, target);
78388 env->has_this = 1;
78389 DUK_HOBJENV_ASSERT_VALID(env);
78390 DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env));
78391
78392 DUK_ASSERT(act == thr->callstack_curr);
78393 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
78394 DUK_ASSERT(act->lex_env != NULL);
78395 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env);
78396 act->lex_env = (duk_hobject *) env; /* Now reachable. */
78397 DUK_HOBJECT_INCREF(thr, (duk_hobject *) env);
78398 /* Net refcount change to act->lex_env is 0: incref for env's
78399 * prototype, decref for act->lex_env overwrite.
78400 */
78401
78402 /* Set catcher lex_env active (affects unwind)
78403 * only when the whole setup is complete.
78404 */
78405 cat = act->cat; /* XXX: better to relookup? not mandatory because 'cat' is stable */
78406 cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
78407 } else {
78408 ;
78409 }
78410
78411 DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, "
78412 "idx_base=%ld, h_varname=%!O",
78413 (unsigned long) cat->flags,
78414 (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
78415
78416 duk_pop_unsafe(thr);
78417}
78418
78419DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) {
78420 duk_activation *act;
78421 duk_catcher *cat;
78422 duk_tval *tv1;
78423 duk_instr_t *pc_base;
78424
78425 DUK_UNREF(ins);
78426
78427 DUK_ASSERT(thr->callstack_top >= 1);
78428 act = thr->callstack_curr;
78429 DUK_ASSERT(act != NULL);
78430 cat = act->cat;
78431 DUK_ASSERT(cat != NULL);
78432 DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
78433
78434 DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
78435 DUK_CAT_CLEAR_CATCH_ENABLED(cat);
78436
78437 pc_base = cat->pc_base;
78438
78439 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
78440 DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
78441
78442 tv1 = thr->valstack + cat->idx_base;
78443 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
78444 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
78445 tv1 = NULL;
78446
78447 tv1 = thr->valstack + cat->idx_base + 1;
78448 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
78449 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
78450 tv1 = NULL;
78451
78452 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
78453 } else {
78454 DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
78455
78456 duk_hthread_catcher_unwind_norz(thr, act); /* lexenv may be set for 'with' binding */
78457 /* no need to unwind callstack */
78458 }
78459
78460 return pc_base + 1; /* new curr_pc value */
78461}
78462
78463DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) {
78464 duk_activation *act;
78465 duk_catcher *cat;
78466 duk_tval *tv1;
78467 duk_instr_t *pc_base;
78468
78469 DUK_UNREF(ins);
78470
78471 DUK_ASSERT(thr->callstack_top >= 1);
78472 act = thr->callstack_curr;
78473 DUK_ASSERT(act != NULL);
78474 cat = act->cat;
78475 DUK_ASSERT(cat != NULL);
78476 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
78477
78478 if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
78479 duk_hobject *prev_env;
78480
78481 /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
78482 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
78483 DUK_ASSERT(act->lex_env != NULL);
78484
78485 DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
78486
78487 prev_env = act->lex_env;
78488 DUK_ASSERT(prev_env != NULL);
78489 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
78490 DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
78491 DUK_HOBJECT_INCREF(thr, act->lex_env);
78492 DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
78493
78494 DUK_ASSERT(act == thr->callstack_curr);
78495 DUK_ASSERT(act != NULL);
78496 }
78497
78498 pc_base = cat->pc_base;
78499
78500 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
78501 DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
78502
78503 tv1 = thr->valstack + cat->idx_base;
78504 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
78505 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
78506 tv1 = NULL;
78507
78508 tv1 = thr->valstack + cat->idx_base + 1;
78509 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
78510 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
78511 tv1 = NULL;
78512
78513 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
78514 } else {
78515 DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
78516
78517 duk_hthread_catcher_unwind_norz(thr, act);
78518 /* no need to unwind callstack */
78519 }
78520
78521 return pc_base + 1; /* new curr_pc value */
78522}
78523
78524DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) {
78525 duk_activation *act;
78526 duk_tval *tv1;
78527 duk_uint_t reg_catch;
78528 duk_small_uint_t cont_type;
78529 duk_small_uint_t ret_result;
78530
78531 DUK_ASSERT(thr->ptr_curr_pc == NULL);
78532 DUK_ASSERT(thr->callstack_top >= 1);
78533 act = thr->callstack_curr;
78534 DUK_ASSERT(act != NULL);
78535 reg_catch = DUK_DEC_ABC(ins);
78536
78537 /* CATCH flag may be enabled or disabled here; it may be enabled if
78538 * the statement has a catch block but the try block does not throw
78539 * an error.
78540 */
78541
78542 DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
78543 (duk_tval *) (thr->valstack_bottom + reg_catch + 0),
78544 (duk_tval *) (thr->valstack_bottom + reg_catch + 1)));
78545
78546 tv1 = thr->valstack_bottom + reg_catch + 1; /* type */
78547 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
78548#if defined(DUK_USE_FASTINT)
78549 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
78550 cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
78551#else
78552 cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
78553#endif
78554
78555 tv1--; /* value */
78556
78557 switch (cont_type) {
78558 case DUK_LJ_TYPE_NORMAL: {
78559 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
78560 "dismantle catcher, resume execution after ENDFIN"));
78561
78562 duk_hthread_catcher_unwind_norz(thr, act);
78563 /* no need to unwind callstack */
78564 return 0; /* restart execution */
78565 }
78566 case DUK_LJ_TYPE_RETURN: {
78567 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
78568 "catcher, handle return, lj.value1=%!T", tv1));
78569
78570 /* Not necessary to unwind catch stack: return handling will
78571 * do it. The finally flag of 'cat' is no longer set. The
78572 * catch flag may be set, but it's not checked by return handling.
78573 */
78574
78575 duk_push_tval(thr, tv1);
78576 ret_result = duk__handle_return(thr, entry_act);
78577 if (ret_result == DUK__RETHAND_RESTART) {
78578 return 0; /* restart execution */
78579 }
78580 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
78581
78582 DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
78583 return 1; /* exit executor */
78584 }
78585 case DUK_LJ_TYPE_BREAK:
78586 case DUK_LJ_TYPE_CONTINUE: {
78587 duk_uint_t label_id;
78588 duk_small_uint_t lj_type;
78589
78590 /* Not necessary to unwind catch stack: break/continue
78591 * handling will do it. The finally flag of 'cat' is
78592 * no longer set. The catch flag may be set, but it's
78593 * not checked by break/continue handling.
78594 */
78595
78596 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
78597#if defined(DUK_USE_FASTINT)
78598 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
78599 label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
78600#else
78601 label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
78602#endif
78603 lj_type = cont_type;
78604 duk__handle_break_or_continue(thr, label_id, lj_type);
78605 return 0; /* restart execution */
78606 }
78607 default: {
78608 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
78609 "dismantle catcher, re-throw error",
78610 (long) cont_type));
78611
78612 duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1);
78613 /* No debugger Throw notify check on purpose (rethrow). */
78614
78615 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
78616 duk_err_longjmp(thr);
78617 DUK_UNREACHABLE();
78618 }
78619 }
78620
78621 DUK_UNREACHABLE();
78622 return 0;
78623}
78624
78625DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) {
78626 duk_small_uint_t b;
78627 duk_small_uint_t c;
78628
78629 /*
78630 * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
78631 * If called with 'null' or 'undefined', this opcode returns 'null' as
78632 * the enumerator, which is special cased in NEXTENUM. This simplifies
78633 * the compiler part
78634 */
78635
78636 /* B -> register for writing enumerator object
78637 * C -> value to be enumerated (register)
78638 */
78639 b = DUK_DEC_B(ins);
78640 c = DUK_DEC_C(ins);
78641
78642 if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) {
78643 duk_push_null(thr);
78644 duk_replace(thr, (duk_idx_t) b);
78645 } else {
78646 duk_dup(thr, (duk_idx_t) c);
78647 duk_to_object(thr, -1);
78648 duk_hobject_enumerator_create(thr, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
78649 duk_replace(thr, (duk_idx_t) b);
78650 }
78651}
78652
78653DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) {
78654 duk_small_uint_t b;
78655 duk_small_uint_t c;
78656 duk_small_uint_t pc_skip = 0;
78657
78658 /*
78659 * NEXTENUM checks whether the enumerator still has unenumerated
78660 * keys. If so, the next key is loaded to the target register
78661 * and the next instruction is skipped. Otherwise the next instruction
78662 * will be executed, jumping out of the enumeration loop.
78663 */
78664
78665 /* B -> target register for next key
78666 * C -> enum register
78667 */
78668 b = DUK_DEC_B(ins);
78669 c = DUK_DEC_C(ins);
78670
78671 DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
78672 (duk_tval *) duk_get_tval(thr, (duk_idx_t) b),
78673 (duk_tval *) duk_get_tval(thr, (duk_idx_t) c)));
78674
78675 if (duk_is_object(thr, (duk_idx_t) c)) {
78676 /* XXX: assert 'c' is an enumerator */
78677 duk_dup(thr, (duk_idx_t) c);
78678 if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) {
78679 /* [ ... enum ] -> [ ... next_key ] */
78680 DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
78681 (duk_tval *) duk_get_tval(thr, -1)));
78682 pc_skip = 1;
78683 } else {
78684 /* [ ... enum ] -> [ ... ] */
78685 DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
78686 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
78687 thr->valstack_top++;
78688 }
78689 duk_replace(thr, (duk_idx_t) b);
78690 } else {
78691 /* 'null' enumerator case -> behave as with an empty enumerator */
78692 DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c));
78693 DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
78694 }
78695
78696 return pc_skip;
78697}
78698
78699/*
78700 * Call handling helpers.
78701 */
78702
78703DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, duk_idx_t nargs, duk_small_uint_t call_flags) {
78704 duk_bool_t rc;
78705
78706 duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
78707
78708 /* Attempt an Ecma-to-Ecma call setup. If the call
78709 * target is (directly or indirectly) Reflect.construct(),
78710 * the call may change into a constructor call on the fly.
78711 */
78712 rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags);
78713 if (rc != 0) {
78714 /* Ecma-to-ecma call possible, may or may not
78715 * be a tail call. Avoid C recursion by
78716 * reusing current executor instance.
78717 */
78718 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
78719 /* curr_pc synced by duk_handle_call_unprotected() */
78720 DUK_ASSERT(thr->ptr_curr_pc == NULL);
78721 return rc;
78722 } else {
78723 /* Call was handled inline. */
78724 }
78725 DUK_ASSERT(thr->ptr_curr_pc != NULL);
78726 return rc;
78727}
78728
78729/*
78730 * ECMAScript bytecode executor.
78731 *
78732 * Resume execution for the current thread from its current activation.
78733 * Returns when execution would return from the entry level activation,
78734 * leaving a single return value on top of the stack. Function calls
78735 * and thread resumptions are handled internally. If an error occurs,
78736 * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
78737 * setjmp() jmpbuf.
78738 *
78739 * ECMAScript function calls and coroutine resumptions are handled
78740 * internally (by the outer executor function) without recursive C calls.
78741 * Other function calls are handled using duk_handle_call(), increasing
78742 * C recursion depth.
78743 *
78744 * Abrupt completions (= long control tranfers) are handled either
78745 * directly by reconfiguring relevant stacks and restarting execution,
78746 * or via a longjmp. Longjmp-free handling is preferable for performance
78747 * (especially Emscripten performance), and is used for: break, continue,
78748 * and return.
78749 *
78750 * For more detailed notes, see doc/execution.rst.
78751 *
78752 * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
78753 * and volatile.
78754 */
78755
78756/* Presence of 'fun' is config based, there's a marginal performance
78757 * difference and the best option is architecture dependent.
78758 */
78759#if defined(DUK_USE_EXEC_FUN_LOCAL)
78760#define DUK__FUN() fun
78761#else
78762#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr))
78763#endif
78764
78765/* Strict flag. */
78766#define DUK__STRICT() ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
78767
78768/* Reg/const access macros: these are very footprint and performance sensitive
78769 * so modify with care. Arguments are sometimes evaluated multiple times which
78770 * is not ideal.
78771 */
78772#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
78773#define DUK__REGP(x) (thr->valstack_bottom + (x))
78774#define DUK__CONST(x) (*(consts + (x)))
78775#define DUK__CONSTP(x) (consts + (x))
78776
78777/* Reg/const access macros which take the 32-bit instruction and avoid an
78778 * explicit field decoding step by using shifts and masks. These must be
78779 * kept in sync with duk_js_bytecode.h. The shift/mask values are chosen
78780 * so that 'ins' can be shifted and masked and used as a -byte- offset
78781 * instead of a duk_tval offset which needs further shifting (which is an
78782 * issue on some, but not all, CPUs).
78783 */
78784#define DUK__RCBIT_B DUK_BC_REGCONST_B
78785#define DUK__RCBIT_C DUK_BC_REGCONST_C
78786#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
78787#if defined(DUK_USE_PACKED_TVAL)
78788#define DUK__TVAL_SHIFT 3 /* sizeof(duk_tval) == 8 */
78789#else
78790#define DUK__TVAL_SHIFT 4 /* sizeof(duk_tval) == 16; not always the case so also asserted for */
78791#endif
78792#define DUK__SHIFT_A (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT)
78793#define DUK__SHIFT_B (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT)
78794#define DUK__SHIFT_C (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT)
78795#define DUK__SHIFT_BC (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT)
78796#define DUK__MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT)
78797#define DUK__MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT)
78798#define DUK__MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT)
78799#define DUK__MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT)
78800#define DUK__BYTEOFF_A(ins) (((ins) >> DUK__SHIFT_A) & DUK__MASK_A)
78801#define DUK__BYTEOFF_B(ins) (((ins) >> DUK__SHIFT_B) & DUK__MASK_B)
78802#define DUK__BYTEOFF_C(ins) (((ins) >> DUK__SHIFT_C) & DUK__MASK_C)
78803#define DUK__BYTEOFF_BC(ins) (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC)
78804
78805#define DUK__REGP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins))))
78806#define DUK__REGP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins))))
78807#define DUK__REGP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins))))
78808#define DUK__REGP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins))))
78809#define DUK__CONSTP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins))))
78810#define DUK__CONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins))))
78811#define DUK__CONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins))))
78812#define DUK__CONSTP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins))))
78813#define DUK__REGCONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins))))
78814#define DUK__REGCONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins))))
78815#else /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
78816/* Safe alternatives, no assumption about duk_tval size. */
78817#define DUK__REGP_A(ins) DUK__REGP(DUK_DEC_A((ins)))
78818#define DUK__REGP_B(ins) DUK__REGP(DUK_DEC_B((ins)))
78819#define DUK__REGP_C(ins) DUK__REGP(DUK_DEC_C((ins)))
78820#define DUK__REGP_BC(ins) DUK__REGP(DUK_DEC_BC((ins)))
78821#define DUK__CONSTP_A(ins) DUK__CONSTP(DUK_DEC_A((ins)))
78822#define DUK__CONSTP_B(ins) DUK__CONSTP(DUK_DEC_B((ins)))
78823#define DUK__CONSTP_C(ins) DUK__CONSTP(DUK_DEC_C((ins)))
78824#define DUK__CONSTP_BC(ins) DUK__CONSTP(DUK_DEC_BC((ins)))
78825#define DUK__REGCONSTP_B(ins) ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins)))
78826#define DUK__REGCONSTP_C(ins) ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins)))
78827#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
78828
78829#if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
78830#define DUK__INTERNAL_ERROR(msg) do { \
78831 DUK_ERROR_ERROR(thr, (msg)); \
78832 DUK_WO_NORETURN(return;); \
78833 } while (0)
78834#else
78835#define DUK__INTERNAL_ERROR(msg) do { \
78836 goto internal_error; \
78837 } while (0)
78838#endif
78839
78840#define DUK__SYNC_CURR_PC() do { \
78841 duk_activation *duk__act; \
78842 duk__act = thr->callstack_curr; \
78843 duk__act->curr_pc = curr_pc; \
78844 } while (0)
78845#define DUK__SYNC_AND_NULL_CURR_PC() do { \
78846 duk_activation *duk__act; \
78847 duk__act = thr->callstack_curr; \
78848 duk__act->curr_pc = curr_pc; \
78849 thr->ptr_curr_pc = NULL; \
78850 } while (0)
78851
78852#if defined(DUK_USE_EXEC_PREFER_SIZE)
78853#define DUK__LOOKUP_INDIRECT(idx) do { \
78854 (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \
78855 } while (0)
78856#elif defined(DUK_USE_FASTINT)
78857#define DUK__LOOKUP_INDIRECT(idx) do { \
78858 duk_tval *tv_ind; \
78859 tv_ind = DUK__REGP((idx)); \
78860 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
78861 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind)); /* compiler guarantees */ \
78862 (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \
78863 } while (0)
78864#else
78865#define DUK__LOOKUP_INDIRECT(idx) do { \
78866 duk_tval *tv_ind; \
78867 tv_ind = DUK__REGP(idx); \
78868 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
78869 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \
78870 } while (0)
78871#endif
78872
78873DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
78874 duk_activation *entry_act,
78875 duk_int_t entry_call_recursion_depth,
78876 duk_jmpbuf *entry_jmpbuf_ptr,
78877 volatile duk_bool_t *out_delayed_catch_setup) {
78878 duk_small_uint_t lj_ret;
78879
78880 /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
78881 * before longjmp.
78882 */
78883 DUK_ASSERT(heap->curr_thread != NULL);
78884 DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
78885
78886 /* XXX: signalling the need to shrink check (only if unwound) */
78887
78888 /* Must be restored here to handle e.g. yields properly. */
78889 heap->call_recursion_depth = entry_call_recursion_depth;
78890
78891 /* Switch to caller's setjmp() catcher so that if an error occurs
78892 * during error handling, it is always propagated outwards instead
78893 * of causing an infinite loop in our own handler.
78894 */
78895 heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
78896
78897 lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act, out_delayed_catch_setup);
78898
78899 /* Error handling complete, remove side effect protections.
78900 */
78901#if defined(DUK_USE_ASSERTIONS)
78902 DUK_ASSERT(heap->error_not_allowed == 1);
78903 heap->error_not_allowed = 0;
78904#endif
78905 DUK_ASSERT(heap->pf_prevent_count > 0);
78906 heap->pf_prevent_count--;
78907 DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count));
78908
78909 if (lj_ret == DUK__LONGJMP_RESTART) {
78910 /* Restart bytecode execution, possibly with a changed thread. */
78911 DUK_REFZERO_CHECK_SLOW(heap->curr_thread);
78912 } else {
78913 /* If an error is propagated, don't run refzero checks here.
78914 * The next catcher will deal with that. Pf_prevent_count
78915 * will be re-bumped by the longjmp.
78916 */
78917
78918 DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */
78919 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */
78920
78921 /* Thread may have changed, e.g. YIELD converted to THROW. */
78922 duk_err_longjmp(heap->curr_thread);
78923 DUK_UNREACHABLE();
78924 }
78925}
78926
78927/* Outer executor with setjmp/longjmp handling. */
78928DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
78929 /* Entry level info. */
78930 duk_hthread *entry_thread;
78931 duk_activation *entry_act;
78932 duk_int_t entry_call_recursion_depth;
78933 duk_jmpbuf *entry_jmpbuf_ptr;
78934 duk_jmpbuf our_jmpbuf;
78935 duk_heap *heap;
78936 volatile duk_bool_t delayed_catch_setup = 0;
78937
78938 DUK_ASSERT(exec_thr != NULL);
78939 DUK_ASSERT(exec_thr->heap != NULL);
78940 DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
78941 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
78942 DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
78943 DUK_ASSERT(exec_thr->callstack_curr != NULL);
78944 DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL);
78945 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr)));
78946
78947 DUK_GC_TORTURE(exec_thr->heap);
78948
78949 entry_thread = exec_thr;
78950 heap = entry_thread->heap;
78951 entry_act = entry_thread->callstack_curr;
78952 DUK_ASSERT(entry_act != NULL);
78953 entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
78954 entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
78955
78956 /*
78957 * Note: we currently assume that the setjmp() catchpoint is
78958 * not re-entrant (longjmp() cannot be called more than once
78959 * for a single setjmp()).
78960 *
78961 * See doc/code-issues.rst for notes on variable assignment
78962 * before and after setjmp().
78963 */
78964
78965 for (;;) {
78966 heap->lj.jmpbuf_ptr = &our_jmpbuf;
78967 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
78968
78969#if defined(DUK_USE_CPP_EXCEPTIONS)
78970 try {
78971#else
78972 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
78973 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
78974#endif
78975 DUK_DDD(DUK_DDDPRINT("after setjmp, delayed catch setup: %ld\n", (long) delayed_catch_setup));
78976
78977 if (DUK_UNLIKELY(delayed_catch_setup != 0)) {
78978 duk_hthread *thr = entry_thread->heap->curr_thread;
78979
78980 delayed_catch_setup = 0;
78981 duk__handle_catch_part2(thr);
78982 DUK_ASSERT(delayed_catch_setup == 0);
78983 DUK_DDD(DUK_DDDPRINT("top after delayed catch setup: %ld", (long) duk_get_top(entry_thread)));
78984 }
78985
78986 /* Execute bytecode until returned or longjmp(). */
78987 duk__js_execute_bytecode_inner(entry_thread, entry_act);
78988
78989 /* Successful return: restore jmpbuf and return to caller. */
78990 heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
78991
78992 return;
78993#if defined(DUK_USE_CPP_EXCEPTIONS)
78994 } catch (duk_internal_exception &exc) {
78995#else
78996 } else {
78997#endif
78998#if defined(DUK_USE_CPP_EXCEPTIONS)
78999 DUK_UNREF(exc);
79000#endif
79001 DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
79002 DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
79003
79004 duk__handle_executor_error(heap,
79005 entry_act,
79006 entry_call_recursion_depth,
79007 entry_jmpbuf_ptr,
79008 &delayed_catch_setup);
79009 }
79010#if defined(DUK_USE_CPP_EXCEPTIONS)
79011 catch (duk_fatal_exception &exc) {
79012 DUK_D(DUK_DPRINT("rethrow duk_fatal_exception"));
79013 DUK_UNREF(exc);
79014 throw;
79015 } catch (std::exception &exc) {
79016 const char *what = exc.what();
79017 if (!what) {
79018 what = "unknown";
79019 }
79020 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
79021 DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
79022 try {
79023 DUK_ASSERT(heap->curr_thread != NULL);
79024 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
79025 DUK_WO_NORETURN(return;);
79026 } catch (duk_internal_exception exc) {
79027 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
79028 DUK_UNREF(exc);
79029 duk__handle_executor_error(heap,
79030 entry_act,
79031 entry_call_recursion_depth,
79032 entry_jmpbuf_ptr,
79033 &delayed_catch_setup);
79034 }
79035 } catch (...) {
79036 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
79037 DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
79038 try {
79039 DUK_ASSERT(heap->curr_thread != NULL);
79040 DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
79041 DUK_WO_NORETURN(return;);
79042 } catch (duk_internal_exception exc) {
79043 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
79044 DUK_UNREF(exc);
79045 duk__handle_executor_error(heap,
79046 entry_act,
79047 entry_call_recursion_depth,
79048 entry_jmpbuf_ptr,
79049 &delayed_catch_setup);
79050 }
79051 }
79052#endif
79053 }
79054
79055 DUK_WO_NORETURN(return;);
79056}
79057
79058/* Inner executor, performance critical. */
79059DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) {
79060 /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
79061 * Critical for performance. It would be safest to make this volatile,
79062 * but that eliminates performance benefits; aliasing guarantees
79063 * should be enough though.
79064 */
79065 duk_instr_t *curr_pc; /* bytecode has a stable pointer */
79066
79067 /* Hot variables for interpretation. Critical for performance,
79068 * but must add sparingly to minimize register shuffling.
79069 */
79070 duk_hthread *thr; /* stable */
79071 duk_tval *consts; /* stable */
79072 duk_uint_fast32_t ins;
79073 /* 'funcs' is quite rarely used, so no local for it */
79074#if defined(DUK_USE_EXEC_FUN_LOCAL)
79075 duk_hcompfunc *fun;
79076#else
79077 /* 'fun' is quite rarely used, so no local for it */
79078#endif
79079
79080#if defined(DUK_USE_INTERRUPT_COUNTER)
79081 duk_int_t int_ctr;
79082#endif
79083
79084#if defined(DUK_USE_ASSERTIONS)
79085 duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
79086#endif
79087
79088 /* Optimized reg/const access macros assume sizeof(duk_tval) to be
79089 * either 8 or 16. Heap allocation checks this even without asserts
79090 * enabled now because it can't be autodetected in duk_config.h.
79091 */
79092#if 1
79093#if defined(DUK_USE_PACKED_TVAL)
79094 DUK_ASSERT(sizeof(duk_tval) == 8);
79095#else
79096 DUK_ASSERT(sizeof(duk_tval) == 16);
79097#endif
79098#endif
79099
79100 DUK_GC_TORTURE(entry_thread->heap);
79101
79102 /*
79103 * Restart execution by reloading thread state.
79104 *
79105 * Note that 'thr' and any thread configuration may have changed,
79106 * so all local variables are suspect and we need to reinitialize.
79107 *
79108 * The number of local variables should be kept to a minimum: if
79109 * the variables are spilled, they will need to be loaded from
79110 * memory anyway.
79111 *
79112 * Any 'goto restart_execution;' code path in opcode dispatch must
79113 * ensure 'curr_pc' is synced back to act->curr_pc before the goto
79114 * takes place.
79115 *
79116 * The interpreter must be very careful with memory pointers, as
79117 * many pointers are not guaranteed to be 'stable' and may be
79118 * reallocated and relocated on-the-fly quite easily (e.g. by a
79119 * memory allocation or a property access).
79120 *
79121 * The following are assumed to have stable pointers:
79122 * - the current thread
79123 * - the current function
79124 * - the bytecode, constant table, inner function table of the
79125 * current function (as they are a part of the function allocation)
79126 *
79127 * The following are assumed to have semi-stable pointers:
79128 * - the current activation entry: stable as long as callstack
79129 * is not changed (reallocated by growing or shrinking), or
79130 * by any garbage collection invocation (through finalizers)
79131 * - Note in particular that ANY DECREF can invalidate the
79132 * activation pointer, so for the most part a fresh lookup
79133 * is required
79134 *
79135 * The following are not assumed to have stable pointers at all:
79136 * - the value stack (registers) of the current thread
79137 *
79138 * See execution.rst for discussion.
79139 */
79140
79141 restart_execution:
79142
79143 /* Lookup current thread; use the stable 'entry_thread' for this to
79144 * avoid clobber warnings. Any valid, reachable 'thr' value would be
79145 * fine for this, so using 'entry_thread' is just to silence warnings.
79146 */
79147 thr = entry_thread->heap->curr_thread;
79148 DUK_ASSERT(thr != NULL);
79149 DUK_ASSERT(thr->callstack_top >= 1);
79150 DUK_ASSERT(thr->callstack_curr != NULL);
79151 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
79152 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
79153
79154 DUK_GC_TORTURE(thr->heap);
79155
79156 thr->ptr_curr_pc = &curr_pc;
79157
79158 /* Relookup and initialize dispatch loop variables. Debugger check. */
79159 {
79160 duk_activation *act;
79161#if !defined(DUK_USE_EXEC_FUN_LOCAL)
79162 duk_hcompfunc *fun;
79163#endif
79164
79165 /* Assume interrupt init/counter are properly initialized here. */
79166 /* Assume that thr->valstack_bottom has been set-up before getting here. */
79167
79168 act = thr->callstack_curr;
79169 DUK_ASSERT(act != NULL);
79170 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
79171 DUK_ASSERT(fun != NULL);
79172 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
79173 consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun);
79174 DUK_ASSERT(consts != NULL);
79175
79176#if defined(DUK_USE_DEBUGGER_SUPPORT)
79177 if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) {
79178 duk__executor_recheck_debugger(thr, act, fun);
79179 DUK_ASSERT(act == thr->callstack_curr);
79180 DUK_ASSERT(act != NULL);
79181 }
79182#endif /* DUK_USE_DEBUGGER_SUPPORT */
79183
79184#if defined(DUK_USE_ASSERTIONS)
79185 valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
79186#endif
79187
79188 /* Set up curr_pc for opcode dispatch. */
79189 curr_pc = act->curr_pc;
79190 }
79191
79192 DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
79193 "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, "
79194 "preventcount=%ld",
79195 (void *) thr,
79196 (long) (thr->callstack_top - 1),
79197 (void *) DUK__FUN(),
79198 (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
79199 (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
79200 (long) (thr->callstack_top - 1),
79201 (long) (thr->valstack_bottom - thr->valstack),
79202 (long) (thr->valstack_top - thr->valstack),
79203 (long) thr->callstack_preventcount));
79204
79205 /* Dispatch loop. */
79206
79207 for (;;) {
79208 duk_uint8_t op;
79209
79210 DUK_ASSERT(thr->callstack_top >= 1);
79211 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
79212 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
79213
79214 /* Executor interrupt counter check, used to implement breakpoints,
79215 * debugging interface, execution timeouts, etc. The counter is heap
79216 * specific but is maintained in the current thread to make the check
79217 * as fast as possible. The counter is copied back to the heap struct
79218 * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
79219 */
79220#if defined(DUK_USE_INTERRUPT_COUNTER)
79221 int_ctr = thr->interrupt_counter;
79222 if (DUK_LIKELY(int_ctr > 0)) {
79223 thr->interrupt_counter = int_ctr - 1;
79224 } else {
79225 /* Trigger at zero or below */
79226 duk_small_uint_t exec_int_ret;
79227
79228 DUK_STATS_INC(thr->heap, stats_exec_interrupt);
79229
79230 /* Write curr_pc back for the debugger. */
79231 {
79232 duk_activation *act;
79233 DUK_ASSERT(thr->callstack_top > 0);
79234 act = thr->callstack_curr;
79235 DUK_ASSERT(act != NULL);
79236 act->curr_pc = (duk_instr_t *) curr_pc;
79237 }
79238
79239 /* Forced restart caused by a function return; must recheck
79240 * debugger breakpoints before checking line transitions,
79241 * see GH-303. Restart and then handle interrupt_counter
79242 * zero again.
79243 */
79244#if defined(DUK_USE_DEBUGGER_SUPPORT)
79245 if (thr->heap->dbg_force_restart) {
79246 DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */
79247 thr->heap->dbg_force_restart = 0;
79248 goto restart_execution;
79249 }
79250#endif
79251
79252 exec_int_ret = duk__executor_interrupt(thr);
79253 if (exec_int_ret == DUK__INT_RESTART) {
79254 /* curr_pc synced back above */
79255 goto restart_execution;
79256 }
79257 }
79258#endif /* DUK_USE_INTERRUPT_COUNTER */
79259#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
79260 /* For cross-checking during development: ensure dispatch count
79261 * matches cumulative interrupt counter init value sums.
79262 */
79263 thr->heap->inst_count_exec++;
79264#endif
79265
79266#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
79267 {
79268 duk_activation *act;
79269 act = thr->callstack_curr;
79270 DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN()));
79271 DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN()));
79272 DUK_UNREF(act); /* if debugging disabled */
79273
79274 DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
79275 (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())),
79276 (unsigned long) *curr_pc,
79277 (long) DUK_DEC_OP(*curr_pc),
79278 (long) (thr->valstack_top - thr->valstack),
79279 (long) (thr->valstack_end - thr->valstack),
79280 (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
79281 (duk_instr_t) *curr_pc));
79282 }
79283#endif
79284
79285#if defined(DUK_USE_ASSERTIONS)
79286 /* Quite heavy assert: check valstack policy. Improper
79287 * shuffle instructions can write beyond valstack_top/end
79288 * so this check catches them in the act.
79289 */
79290 {
79291 duk_tval *tv;
79292 tv = thr->valstack_top;
79293 while (tv != thr->valstack_end) {
79294 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
79295 tv++;
79296 }
79297 }
79298#endif
79299
79300 ins = *curr_pc++;
79301 DUK_STATS_INC(thr->heap, stats_exec_opcodes);
79302
79303 /* Typing: use duk_small_(u)int_fast_t when decoding small
79304 * opcode fields (op, A, B, C, BC) which fit into 16 bits
79305 * and duk_(u)int_fast_t when decoding larger fields (e.g.
79306 * ABC). Use unsigned variant by default, signed when the
79307 * value is used in signed arithmetic. Using variable names
79308 * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot
79309 * typing mismatches.
79310 */
79311
79312 /* Switch based on opcode. Cast to 8-bit unsigned value and
79313 * use a fully populated case clauses so that the compiler
79314 * will (at least usually) omit a bounds check.
79315 */
79316 op = (duk_uint8_t) DUK_DEC_OP(ins);
79317 switch (op) {
79318
79319 /* Some useful macros. These access inner executor variables
79320 * directly so they only apply within the executor.
79321 */
79322#if defined(DUK_USE_EXEC_PREFER_SIZE)
79323#define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; }
79324#define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; }
79325#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
79326 duk_bool_t duk__bval; \
79327 duk__bval = (bval); \
79328 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
79329 duk_push_boolean(thr, duk__bval); \
79330 DUK__REPLACE_TOP_A_BREAK(); \
79331 }
79332#else
79333#define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; }
79334#define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; }
79335#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
79336 duk_bool_t duk__bval; \
79337 duk_tval *duk__tvdst; \
79338 duk__bval = (bval); \
79339 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
79340 duk__tvdst = DUK__REGP_A(ins); \
79341 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \
79342 break; \
79343 }
79344#endif
79345
79346 /* XXX: 12 + 12 bit variant might make sense too, for both reg and
79347 * const loads.
79348 */
79349
79350 /* For LDREG, STREG, LDCONST footprint optimized variants would just
79351 * duk_dup() + duk_replace(), but because they're used quite a lot
79352 * they're currently intentionally not size optimized.
79353 */
79354 case DUK_OP_LDREG: {
79355 duk_tval *tv1, *tv2;
79356
79357 tv1 = DUK__REGP_A(ins);
79358 tv2 = DUK__REGP_BC(ins);
79359 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
79360 break;
79361 }
79362
79363 case DUK_OP_STREG: {
79364 duk_tval *tv1, *tv2;
79365
79366 tv1 = DUK__REGP_A(ins);
79367 tv2 = DUK__REGP_BC(ins);
79368 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
79369 break;
79370 }
79371
79372 case DUK_OP_LDCONST: {
79373 duk_tval *tv1, *tv2;
79374
79375 tv1 = DUK__REGP_A(ins);
79376 tv2 = DUK__CONSTP_BC(ins);
79377 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
79378 break;
79379 }
79380
79381 /* LDINT and LDINTX are intended to load an arbitrary signed
79382 * 32-bit value. Only an LDINT+LDINTX sequence is supported.
79383 * This also guarantees all values remain fastints.
79384 */
79385#if defined(DUK_USE_EXEC_PREFER_SIZE)
79386 case DUK_OP_LDINT: {
79387 duk_int32_t val;
79388
79389 val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
79390 duk_push_int(thr, val);
79391 DUK__REPLACE_TOP_A_BREAK();
79392 }
79393 case DUK_OP_LDINTX: {
79394 duk_int32_t val;
79395
79396 val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins));
79397 val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
79398 duk_push_int(thr, val);
79399 DUK__REPLACE_TOP_A_BREAK();
79400 }
79401#else /* DUK_USE_EXEC_PREFER_SIZE */
79402 case DUK_OP_LDINT: {
79403 duk_tval *tv1;
79404 duk_int32_t val;
79405
79406 val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
79407 tv1 = DUK__REGP_A(ins);
79408 DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
79409 break;
79410 }
79411 case DUK_OP_LDINTX: {
79412 duk_tval *tv1;
79413 duk_int32_t val;
79414
79415 tv1 = DUK__REGP_A(ins);
79416 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
79417#if defined(DUK_USE_FASTINT)
79418 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
79419 val = DUK_TVAL_GET_FASTINT_I32(tv1);
79420#else
79421 /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */
79422 val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1);
79423#endif
79424 val = (duk_int32_t) ((duk_uint32_t) val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
79425 DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
79426 break;
79427 }
79428#endif /* DUK_USE_EXEC_PREFER_SIZE */
79429
79430#if defined(DUK_USE_EXEC_PREFER_SIZE)
79431 case DUK_OP_LDTHIS: {
79432 duk_push_this(thr);
79433 DUK__REPLACE_TOP_BC_BREAK();
79434 }
79435 case DUK_OP_LDUNDEF: {
79436 duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins));
79437 break;
79438 }
79439 case DUK_OP_LDNULL: {
79440 duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins));
79441 break;
79442 }
79443 case DUK_OP_LDTRUE: {
79444 duk_push_true(thr);
79445 DUK__REPLACE_TOP_BC_BREAK();
79446 }
79447 case DUK_OP_LDFALSE: {
79448 duk_push_false(thr);
79449 DUK__REPLACE_TOP_BC_BREAK();
79450 }
79451#else /* DUK_USE_EXEC_PREFER_SIZE */
79452 case DUK_OP_LDTHIS: {
79453 /* Note: 'this' may be bound to any value, not just an object */
79454 duk_tval *tv1, *tv2;
79455
79456 tv1 = DUK__REGP_BC(ins);
79457 tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
79458 DUK_ASSERT(tv2 >= thr->valstack);
79459 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
79460 break;
79461 }
79462 case DUK_OP_LDUNDEF: {
79463 duk_tval *tv1;
79464
79465 tv1 = DUK__REGP_BC(ins);
79466 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
79467 break;
79468 }
79469 case DUK_OP_LDNULL: {
79470 duk_tval *tv1;
79471
79472 tv1 = DUK__REGP_BC(ins);
79473 DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
79474 break;
79475 }
79476 case DUK_OP_LDTRUE: {
79477 duk_tval *tv1;
79478
79479 tv1 = DUK__REGP_BC(ins);
79480 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1); /* side effects */
79481 break;
79482 }
79483 case DUK_OP_LDFALSE: {
79484 duk_tval *tv1;
79485
79486 tv1 = DUK__REGP_BC(ins);
79487 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0); /* side effects */
79488 break;
79489 }
79490#endif /* DUK_USE_EXEC_PREFER_SIZE */
79491
79492 case DUK_OP_BNOT: {
79493 duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
79494 break;
79495 }
79496
79497 case DUK_OP_LNOT: {
79498 duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
79499 break;
79500 }
79501
79502#if defined(DUK_USE_EXEC_PREFER_SIZE)
79503 case DUK_OP_UNM:
79504 case DUK_OP_UNP: {
79505 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op);
79506 break;
79507 }
79508#else /* DUK_USE_EXEC_PREFER_SIZE */
79509 case DUK_OP_UNM: {
79510 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM);
79511 break;
79512 }
79513 case DUK_OP_UNP: {
79514 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP);
79515 break;
79516 }
79517#endif /* DUK_USE_EXEC_PREFER_SIZE */
79518
79519#if defined(DUK_USE_EXEC_PREFER_SIZE)
79520 case DUK_OP_TYPEOF: {
79521 duk_small_uint_t stridx;
79522
79523 stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins));
79524 DUK_ASSERT_STRIDX_VALID(stridx);
79525 duk_push_hstring_stridx(thr, stridx);
79526 DUK__REPLACE_TOP_A_BREAK();
79527 }
79528#else /* DUK_USE_EXEC_PREFER_SIZE */
79529 case DUK_OP_TYPEOF: {
79530 duk_tval *tv;
79531 duk_small_uint_t stridx;
79532 duk_hstring *h_str;
79533
79534 tv = DUK__REGP_BC(ins);
79535 stridx = duk_js_typeof_stridx(tv);
79536 DUK_ASSERT_STRIDX_VALID(stridx);
79537 h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
79538 tv = DUK__REGP_A(ins);
79539 DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
79540 break;
79541 }
79542#endif /* DUK_USE_EXEC_PREFER_SIZE */
79543
79544 case DUK_OP_TYPEOFID: {
79545 duk_small_uint_t stridx;
79546#if !defined(DUK_USE_EXEC_PREFER_SIZE)
79547 duk_hstring *h_str;
79548#endif
79549 duk_activation *act;
79550 duk_hstring *name;
79551 duk_tval *tv;
79552
79553 /* A -> target register
79554 * BC -> constant index of identifier name
79555 */
79556
79557 tv = DUK__CONSTP_BC(ins);
79558 DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
79559 name = DUK_TVAL_GET_STRING(tv);
79560 tv = NULL; /* lookup has side effects */
79561 act = thr->callstack_curr;
79562 if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
79563 /* -> [... val this] */
79564 tv = DUK_GET_TVAL_NEGIDX(thr, -2);
79565 stridx = duk_js_typeof_stridx(tv);
79566 tv = NULL; /* no longer needed */
79567 duk_pop_2_unsafe(thr);
79568 } else {
79569 /* unresolvable, no stack changes */
79570 stridx = DUK_STRIDX_LC_UNDEFINED;
79571 }
79572 DUK_ASSERT_STRIDX_VALID(stridx);
79573#if defined(DUK_USE_EXEC_PREFER_SIZE)
79574 duk_push_hstring_stridx(thr, stridx);
79575 DUK__REPLACE_TOP_A_BREAK();
79576#else /* DUK_USE_EXEC_PREFER_SIZE */
79577 h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
79578 tv = DUK__REGP_A(ins);
79579 DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
79580 break;
79581#endif /* DUK_USE_EXEC_PREFER_SIZE */
79582 }
79583
79584 /* Equality: E5 Sections 11.9.1, 11.9.3 */
79585
79586#define DUK__EQ_BODY(barg,carg) { \
79587 duk_bool_t tmp; \
79588 tmp = duk_js_equals(thr, (barg), (carg)); \
79589 DUK_ASSERT(tmp == 0 || tmp == 1); \
79590 DUK__REPLACE_BOOL_A_BREAK(tmp); \
79591 }
79592#define DUK__NEQ_BODY(barg,carg) { \
79593 duk_bool_t tmp; \
79594 tmp = duk_js_equals(thr, (barg), (carg)); \
79595 DUK_ASSERT(tmp == 0 || tmp == 1); \
79596 tmp ^= 1; \
79597 DUK__REPLACE_BOOL_A_BREAK(tmp); \
79598 }
79599#define DUK__SEQ_BODY(barg,carg) { \
79600 duk_bool_t tmp; \
79601 tmp = duk_js_strict_equals((barg), (carg)); \
79602 DUK_ASSERT(tmp == 0 || tmp == 1); \
79603 DUK__REPLACE_BOOL_A_BREAK(tmp); \
79604 }
79605#define DUK__SNEQ_BODY(barg,carg) { \
79606 duk_bool_t tmp; \
79607 tmp = duk_js_strict_equals((barg), (carg)); \
79608 DUK_ASSERT(tmp == 0 || tmp == 1); \
79609 tmp ^= 1; \
79610 DUK__REPLACE_BOOL_A_BREAK(tmp); \
79611 }
79612#if defined(DUK_USE_EXEC_PREFER_SIZE)
79613 case DUK_OP_EQ_RR:
79614 case DUK_OP_EQ_CR:
79615 case DUK_OP_EQ_RC:
79616 case DUK_OP_EQ_CC:
79617 DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79618 case DUK_OP_NEQ_RR:
79619 case DUK_OP_NEQ_CR:
79620 case DUK_OP_NEQ_RC:
79621 case DUK_OP_NEQ_CC:
79622 DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79623 case DUK_OP_SEQ_RR:
79624 case DUK_OP_SEQ_CR:
79625 case DUK_OP_SEQ_RC:
79626 case DUK_OP_SEQ_CC:
79627 DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79628 case DUK_OP_SNEQ_RR:
79629 case DUK_OP_SNEQ_CR:
79630 case DUK_OP_SNEQ_RC:
79631 case DUK_OP_SNEQ_CC:
79632 DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79633#else /* DUK_USE_EXEC_PREFER_SIZE */
79634 case DUK_OP_EQ_RR:
79635 DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79636 case DUK_OP_EQ_CR:
79637 DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79638 case DUK_OP_EQ_RC:
79639 DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79640 case DUK_OP_EQ_CC:
79641 DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79642 case DUK_OP_NEQ_RR:
79643 DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79644 case DUK_OP_NEQ_CR:
79645 DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79646 case DUK_OP_NEQ_RC:
79647 DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79648 case DUK_OP_NEQ_CC:
79649 DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79650 case DUK_OP_SEQ_RR:
79651 DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79652 case DUK_OP_SEQ_CR:
79653 DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79654 case DUK_OP_SEQ_RC:
79655 DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79656 case DUK_OP_SEQ_CC:
79657 DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79658 case DUK_OP_SNEQ_RR:
79659 DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79660 case DUK_OP_SNEQ_CR:
79661 DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79662 case DUK_OP_SNEQ_RC:
79663 DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79664 case DUK_OP_SNEQ_CC:
79665 DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79666#endif /* DUK_USE_EXEC_PREFER_SIZE */
79667
79668#define DUK__COMPARE_BODY(arg1,arg2,flags) { \
79669 duk_bool_t tmp; \
79670 tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \
79671 DUK_ASSERT(tmp == 0 || tmp == 1); \
79672 DUK__REPLACE_BOOL_A_BREAK(tmp); \
79673 }
79674#define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0)
79675#define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
79676#define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
79677#define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE)
79678#if defined(DUK_USE_EXEC_PREFER_SIZE)
79679 case DUK_OP_GT_RR:
79680 case DUK_OP_GT_CR:
79681 case DUK_OP_GT_RC:
79682 case DUK_OP_GT_CC:
79683 DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79684 case DUK_OP_GE_RR:
79685 case DUK_OP_GE_CR:
79686 case DUK_OP_GE_RC:
79687 case DUK_OP_GE_CC:
79688 DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79689 case DUK_OP_LT_RR:
79690 case DUK_OP_LT_CR:
79691 case DUK_OP_LT_RC:
79692 case DUK_OP_LT_CC:
79693 DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79694 case DUK_OP_LE_RR:
79695 case DUK_OP_LE_CR:
79696 case DUK_OP_LE_RC:
79697 case DUK_OP_LE_CC:
79698 DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
79699#else /* DUK_USE_EXEC_PREFER_SIZE */
79700 case DUK_OP_GT_RR:
79701 DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79702 case DUK_OP_GT_CR:
79703 DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79704 case DUK_OP_GT_RC:
79705 DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79706 case DUK_OP_GT_CC:
79707 DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79708 case DUK_OP_GE_RR:
79709 DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79710 case DUK_OP_GE_CR:
79711 DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79712 case DUK_OP_GE_RC:
79713 DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79714 case DUK_OP_GE_CC:
79715 DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79716 case DUK_OP_LT_RR:
79717 DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79718 case DUK_OP_LT_CR:
79719 DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79720 case DUK_OP_LT_RC:
79721 DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79722 case DUK_OP_LT_CC:
79723 DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79724 case DUK_OP_LE_RR:
79725 DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
79726 case DUK_OP_LE_CR:
79727 DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
79728 case DUK_OP_LE_RC:
79729 DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
79730 case DUK_OP_LE_CC:
79731 DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
79732#endif /* DUK_USE_EXEC_PREFER_SIZE */
79733
79734 /* No size optimized variant at present for IF. */
79735 case DUK_OP_IFTRUE_R: {
79736 if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) {
79737 curr_pc++;
79738 }
79739 break;
79740 }
79741 case DUK_OP_IFTRUE_C: {
79742 if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) {
79743 curr_pc++;
79744 }
79745 break;
79746 }
79747 case DUK_OP_IFFALSE_R: {
79748 if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) {
79749 curr_pc++;
79750 }
79751 break;
79752 }
79753 case DUK_OP_IFFALSE_C: {
79754 if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) {
79755 curr_pc++;
79756 }
79757 break;
79758 }
79759
79760#if defined(DUK_USE_EXEC_PREFER_SIZE)
79761 case DUK_OP_ADD_RR:
79762 case DUK_OP_ADD_CR:
79763 case DUK_OP_ADD_RC:
79764 case DUK_OP_ADD_CC: {
79765 /* XXX: could leave value on stack top and goto replace_top_a; */
79766 duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins));
79767 break;
79768 }
79769#else /* DUK_USE_EXEC_PREFER_SIZE */
79770 case DUK_OP_ADD_RR: {
79771 duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
79772 break;
79773 }
79774 case DUK_OP_ADD_CR: {
79775 duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
79776 break;
79777 }
79778 case DUK_OP_ADD_RC: {
79779 duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
79780 break;
79781 }
79782 case DUK_OP_ADD_CC: {
79783 duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
79784 break;
79785 }
79786#endif /* DUK_USE_EXEC_PREFER_SIZE */
79787
79788#if defined(DUK_USE_EXEC_PREFER_SIZE)
79789 case DUK_OP_SUB_RR:
79790 case DUK_OP_SUB_CR:
79791 case DUK_OP_SUB_RC:
79792 case DUK_OP_SUB_CC:
79793 case DUK_OP_MUL_RR:
79794 case DUK_OP_MUL_CR:
79795 case DUK_OP_MUL_RC:
79796 case DUK_OP_MUL_CC:
79797 case DUK_OP_DIV_RR:
79798 case DUK_OP_DIV_CR:
79799 case DUK_OP_DIV_RC:
79800 case DUK_OP_DIV_CC:
79801 case DUK_OP_MOD_RR:
79802 case DUK_OP_MOD_CR:
79803 case DUK_OP_MOD_RC:
79804 case DUK_OP_MOD_CC:
79805#if defined(DUK_USE_ES7_EXP_OPERATOR)
79806 case DUK_OP_EXP_RR:
79807 case DUK_OP_EXP_CR:
79808 case DUK_OP_EXP_RC:
79809 case DUK_OP_EXP_CC:
79810#endif /* DUK_USE_ES7_EXP_OPERATOR */
79811 {
79812 /* XXX: could leave value on stack top and goto replace_top_a; */
79813 duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
79814 break;
79815 }
79816#else /* DUK_USE_EXEC_PREFER_SIZE */
79817 case DUK_OP_SUB_RR: {
79818 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
79819 break;
79820 }
79821 case DUK_OP_SUB_CR: {
79822 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
79823 break;
79824 }
79825 case DUK_OP_SUB_RC: {
79826 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
79827 break;
79828 }
79829 case DUK_OP_SUB_CC: {
79830 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
79831 break;
79832 }
79833 case DUK_OP_MUL_RR: {
79834 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
79835 break;
79836 }
79837 case DUK_OP_MUL_CR: {
79838 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
79839 break;
79840 }
79841 case DUK_OP_MUL_RC: {
79842 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
79843 break;
79844 }
79845 case DUK_OP_MUL_CC: {
79846 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
79847 break;
79848 }
79849 case DUK_OP_DIV_RR: {
79850 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
79851 break;
79852 }
79853 case DUK_OP_DIV_CR: {
79854 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
79855 break;
79856 }
79857 case DUK_OP_DIV_RC: {
79858 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
79859 break;
79860 }
79861 case DUK_OP_DIV_CC: {
79862 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
79863 break;
79864 }
79865 case DUK_OP_MOD_RR: {
79866 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
79867 break;
79868 }
79869 case DUK_OP_MOD_CR: {
79870 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
79871 break;
79872 }
79873 case DUK_OP_MOD_RC: {
79874 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
79875 break;
79876 }
79877 case DUK_OP_MOD_CC: {
79878 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
79879 break;
79880 }
79881#if defined(DUK_USE_ES7_EXP_OPERATOR)
79882 case DUK_OP_EXP_RR: {
79883 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
79884 break;
79885 }
79886 case DUK_OP_EXP_CR: {
79887 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
79888 break;
79889 }
79890 case DUK_OP_EXP_RC: {
79891 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
79892 break;
79893 }
79894 case DUK_OP_EXP_CC: {
79895 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
79896 break;
79897 }
79898#endif /* DUK_USE_ES7_EXP_OPERATOR */
79899#endif /* DUK_USE_EXEC_PREFER_SIZE */
79900
79901#if defined(DUK_USE_EXEC_PREFER_SIZE)
79902 case DUK_OP_BAND_RR:
79903 case DUK_OP_BAND_CR:
79904 case DUK_OP_BAND_RC:
79905 case DUK_OP_BAND_CC:
79906 case DUK_OP_BOR_RR:
79907 case DUK_OP_BOR_CR:
79908 case DUK_OP_BOR_RC:
79909 case DUK_OP_BOR_CC:
79910 case DUK_OP_BXOR_RR:
79911 case DUK_OP_BXOR_CR:
79912 case DUK_OP_BXOR_RC:
79913 case DUK_OP_BXOR_CC:
79914 case DUK_OP_BASL_RR:
79915 case DUK_OP_BASL_CR:
79916 case DUK_OP_BASL_RC:
79917 case DUK_OP_BASL_CC:
79918 case DUK_OP_BLSR_RR:
79919 case DUK_OP_BLSR_CR:
79920 case DUK_OP_BLSR_RC:
79921 case DUK_OP_BLSR_CC:
79922 case DUK_OP_BASR_RR:
79923 case DUK_OP_BASR_CR:
79924 case DUK_OP_BASR_RC:
79925 case DUK_OP_BASR_CC: {
79926 /* XXX: could leave value on stack top and goto replace_top_a; */
79927 duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
79928 break;
79929 }
79930#else /* DUK_USE_EXEC_PREFER_SIZE */
79931 case DUK_OP_BAND_RR: {
79932 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
79933 break;
79934 }
79935 case DUK_OP_BAND_CR: {
79936 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
79937 break;
79938 }
79939 case DUK_OP_BAND_RC: {
79940 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
79941 break;
79942 }
79943 case DUK_OP_BAND_CC: {
79944 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
79945 break;
79946 }
79947 case DUK_OP_BOR_RR: {
79948 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
79949 break;
79950 }
79951 case DUK_OP_BOR_CR: {
79952 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
79953 break;
79954 }
79955 case DUK_OP_BOR_RC: {
79956 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
79957 break;
79958 }
79959 case DUK_OP_BOR_CC: {
79960 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
79961 break;
79962 }
79963 case DUK_OP_BXOR_RR: {
79964 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
79965 break;
79966 }
79967 case DUK_OP_BXOR_CR: {
79968 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
79969 break;
79970 }
79971 case DUK_OP_BXOR_RC: {
79972 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
79973 break;
79974 }
79975 case DUK_OP_BXOR_CC: {
79976 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
79977 break;
79978 }
79979 case DUK_OP_BASL_RR: {
79980 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
79981 break;
79982 }
79983 case DUK_OP_BASL_CR: {
79984 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
79985 break;
79986 }
79987 case DUK_OP_BASL_RC: {
79988 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
79989 break;
79990 }
79991 case DUK_OP_BASL_CC: {
79992 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
79993 break;
79994 }
79995 case DUK_OP_BLSR_RR: {
79996 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
79997 break;
79998 }
79999 case DUK_OP_BLSR_CR: {
80000 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
80001 break;
80002 }
80003 case DUK_OP_BLSR_RC: {
80004 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
80005 break;
80006 }
80007 case DUK_OP_BLSR_CC: {
80008 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
80009 break;
80010 }
80011 case DUK_OP_BASR_RR: {
80012 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
80013 break;
80014 }
80015 case DUK_OP_BASR_CR: {
80016 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
80017 break;
80018 }
80019 case DUK_OP_BASR_RC: {
80020 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
80021 break;
80022 }
80023 case DUK_OP_BASR_CC: {
80024 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
80025 break;
80026 }
80027#endif /* DUK_USE_EXEC_PREFER_SIZE */
80028
80029 /* For INSTOF and IN, B is always a register. */
80030#define DUK__INSTOF_BODY(barg,carg) { \
80031 duk_bool_t tmp; \
80032 tmp = duk_js_instanceof(thr, (barg), (carg)); \
80033 DUK_ASSERT(tmp == 0 || tmp == 1); \
80034 DUK__REPLACE_BOOL_A_BREAK(tmp); \
80035 }
80036#define DUK__IN_BODY(barg,carg) { \
80037 duk_bool_t tmp; \
80038 tmp = duk_js_in(thr, (barg), (carg)); \
80039 DUK_ASSERT(tmp == 0 || tmp == 1); \
80040 DUK__REPLACE_BOOL_A_BREAK(tmp); \
80041 }
80042#if defined(DUK_USE_EXEC_PREFER_SIZE)
80043 case DUK_OP_INSTOF_RR:
80044 case DUK_OP_INSTOF_CR:
80045 case DUK_OP_INSTOF_RC:
80046 case DUK_OP_INSTOF_CC:
80047 DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
80048 case DUK_OP_IN_RR:
80049 case DUK_OP_IN_CR:
80050 case DUK_OP_IN_RC:
80051 case DUK_OP_IN_CC:
80052 DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
80053#else /* DUK_USE_EXEC_PREFER_SIZE */
80054 case DUK_OP_INSTOF_RR:
80055 DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
80056 case DUK_OP_INSTOF_CR:
80057 DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
80058 case DUK_OP_INSTOF_RC:
80059 DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80060 case DUK_OP_INSTOF_CC:
80061 DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
80062 case DUK_OP_IN_RR:
80063 DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
80064 case DUK_OP_IN_CR:
80065 DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
80066 case DUK_OP_IN_RC:
80067 DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80068 case DUK_OP_IN_CC:
80069 DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
80070#endif /* DUK_USE_EXEC_PREFER_SIZE */
80071
80072 /* Pre/post inc/dec for register variables, important for loops. */
80073#if defined(DUK_USE_EXEC_PREFER_SIZE)
80074 case DUK_OP_PREINCR:
80075 case DUK_OP_PREDECR:
80076 case DUK_OP_POSTINCR:
80077 case DUK_OP_POSTDECR: {
80078 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op);
80079 break;
80080 }
80081 case DUK_OP_PREINCV:
80082 case DUK_OP_PREDECV:
80083 case DUK_OP_POSTINCV:
80084 case DUK_OP_POSTDECV: {
80085 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT());
80086 break;
80087 }
80088#else /* DUK_USE_EXEC_PREFER_SIZE */
80089 case DUK_OP_PREINCR: {
80090 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR);
80091 break;
80092 }
80093 case DUK_OP_PREDECR: {
80094 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR);
80095 break;
80096 }
80097 case DUK_OP_POSTINCR: {
80098 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR);
80099 break;
80100 }
80101 case DUK_OP_POSTDECR: {
80102 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR);
80103 break;
80104 }
80105 case DUK_OP_PREINCV: {
80106 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT());
80107 break;
80108 }
80109 case DUK_OP_PREDECV: {
80110 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT());
80111 break;
80112 }
80113 case DUK_OP_POSTINCV: {
80114 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT());
80115 break;
80116 }
80117 case DUK_OP_POSTDECV: {
80118 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT());
80119 break;
80120 }
80121#endif /* DUK_USE_EXEC_PREFER_SIZE */
80122
80123 /* XXX: Move to separate helper, optimize for perf/size separately. */
80124 /* Preinc/predec for object properties. */
80125 case DUK_OP_PREINCP_RR:
80126 case DUK_OP_PREINCP_CR:
80127 case DUK_OP_PREINCP_RC:
80128 case DUK_OP_PREINCP_CC:
80129 case DUK_OP_PREDECP_RR:
80130 case DUK_OP_PREDECP_CR:
80131 case DUK_OP_PREDECP_RC:
80132 case DUK_OP_PREDECP_CC:
80133 case DUK_OP_POSTINCP_RR:
80134 case DUK_OP_POSTINCP_CR:
80135 case DUK_OP_POSTINCP_RC:
80136 case DUK_OP_POSTINCP_CC:
80137 case DUK_OP_POSTDECP_RR:
80138 case DUK_OP_POSTDECP_CR:
80139 case DUK_OP_POSTDECP_RC:
80140 case DUK_OP_POSTDECP_CC: {
80141 duk_tval *tv_obj;
80142 duk_tval *tv_key;
80143 duk_tval *tv_val;
80144 duk_bool_t rc;
80145 duk_double_t x, y, z;
80146#if !defined(DUK_USE_EXEC_PREFER_SIZE)
80147 duk_tval *tv_dst;
80148#endif /* DUK_USE_EXEC_PREFER_SIZE */
80149
80150 /* A -> target reg
80151 * B -> object reg/const (may be const e.g. in "'foo'[1]")
80152 * C -> key reg/const
80153 */
80154
80155 /* Opcode bits 0-1 are used to distinguish reg/const variants.
80156 * Opcode bits 2-3 are used to distinguish inc/dec variants:
80157 * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1).
80158 */
80159 DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00);
80160 DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04);
80161 DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08);
80162 DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c);
80163
80164 tv_obj = DUK__REGCONSTP_B(ins);
80165 tv_key = DUK__REGCONSTP_C(ins);
80166 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
80167 DUK_UNREF(rc); /* ignore */
80168 tv_obj = NULL; /* invalidated */
80169 tv_key = NULL; /* invalidated */
80170
80171 /* XXX: Fastint fast path would be useful here. Also fastints
80172 * now lose their fastint status in current handling which is
80173 * not intuitive.
80174 */
80175
80176 x = duk_to_number_m1(thr);
80177 duk_pop_unsafe(thr);
80178 if (ins & DUK_BC_INCDECP_FLAG_DEC) {
80179 y = x - 1.0;
80180 } else {
80181 y = x + 1.0;
80182 }
80183
80184 duk_push_number(thr, y);
80185 tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
80186 DUK_ASSERT(tv_val != NULL);
80187 tv_obj = DUK__REGCONSTP_B(ins);
80188 tv_key = DUK__REGCONSTP_C(ins);
80189 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
80190 DUK_UNREF(rc); /* ignore */
80191 tv_obj = NULL; /* invalidated */
80192 tv_key = NULL; /* invalidated */
80193 duk_pop_unsafe(thr);
80194
80195 z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y;
80196#if defined(DUK_USE_EXEC_PREFER_SIZE)
80197 duk_push_number(thr, z);
80198 DUK__REPLACE_TOP_A_BREAK();
80199#else
80200 tv_dst = DUK__REGP_A(ins);
80201 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z);
80202 break;
80203#endif
80204 }
80205
80206 /* XXX: GETPROP where object is 'this', GETPROPT?
80207 * Occurs relatively often in object oriented code.
80208 */
80209
80210#define DUK__GETPROP_BODY(barg,carg) { \
80211 /* A -> target reg \
80212 * B -> object reg/const (may be const e.g. in "'foo'[1]") \
80213 * C -> key reg/const \
80214 */ \
80215 (void) duk_hobject_getprop(thr, (barg), (carg)); \
80216 DUK__REPLACE_TOP_A_BREAK(); \
80217 }
80218#define DUK__GETPROPC_BODY(barg,carg) { \
80219 /* Same as GETPROP but callability check for property-based calls. */ \
80220 duk_tval *tv__targ; \
80221 (void) duk_hobject_getprop(thr, (barg), (carg)); \
80222 DUK_GC_TORTURE(thr->heap); \
80223 tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \
80224 if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \
80225 /* Here we intentionally re-evaluate the macro \
80226 * arguments to deal with potentially changed \
80227 * valstack base pointer! \
80228 */ \
80229 duk_call_setup_propcall_error(thr, (barg), (carg)); \
80230 } \
80231 DUK__REPLACE_TOP_A_BREAK(); \
80232 }
80233#define DUK__PUTPROP_BODY(aarg,barg,carg) { \
80234 /* A -> object reg \
80235 * B -> key reg/const \
80236 * C -> value reg/const \
80237 * \
80238 * Note: intentional difference to register arrangement \
80239 * of e.g. GETPROP; 'A' must contain a register-only value. \
80240 */ \
80241 (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \
80242 break; \
80243 }
80244#define DUK__DELPROP_BODY(barg,carg) { \
80245 /* A -> result reg \
80246 * B -> object reg \
80247 * C -> key reg/const \
80248 */ \
80249 duk_bool_t rc; \
80250 rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \
80251 DUK_ASSERT(rc == 0 || rc == 1); \
80252 DUK__REPLACE_BOOL_A_BREAK(rc); \
80253 }
80254#if defined(DUK_USE_EXEC_PREFER_SIZE)
80255 case DUK_OP_GETPROP_RR:
80256 case DUK_OP_GETPROP_CR:
80257 case DUK_OP_GETPROP_RC:
80258 case DUK_OP_GETPROP_CC:
80259 DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
80260#if defined(DUK_USE_VERBOSE_ERRORS)
80261 case DUK_OP_GETPROPC_RR:
80262 case DUK_OP_GETPROPC_CR:
80263 case DUK_OP_GETPROPC_RC:
80264 case DUK_OP_GETPROPC_CC:
80265 DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
80266#endif
80267 case DUK_OP_PUTPROP_RR:
80268 case DUK_OP_PUTPROP_CR:
80269 case DUK_OP_PUTPROP_RC:
80270 case DUK_OP_PUTPROP_CC:
80271 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
80272 case DUK_OP_DELPROP_RR:
80273 case DUK_OP_DELPROP_RC: /* B is always reg */
80274 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins));
80275#else /* DUK_USE_EXEC_PREFER_SIZE */
80276 case DUK_OP_GETPROP_RR:
80277 DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
80278 case DUK_OP_GETPROP_CR:
80279 DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
80280 case DUK_OP_GETPROP_RC:
80281 DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80282 case DUK_OP_GETPROP_CC:
80283 DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
80284#if defined(DUK_USE_VERBOSE_ERRORS)
80285 case DUK_OP_GETPROPC_RR:
80286 DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
80287 case DUK_OP_GETPROPC_CR:
80288 DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
80289 case DUK_OP_GETPROPC_RC:
80290 DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80291 case DUK_OP_GETPROPC_CC:
80292 DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
80293#endif
80294 case DUK_OP_PUTPROP_RR:
80295 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins));
80296 case DUK_OP_PUTPROP_CR:
80297 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins));
80298 case DUK_OP_PUTPROP_RC:
80299 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80300 case DUK_OP_PUTPROP_CC:
80301 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
80302 case DUK_OP_DELPROP_RR: /* B is always reg */
80303 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
80304 case DUK_OP_DELPROP_RC:
80305 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
80306#endif /* DUK_USE_EXEC_PREFER_SIZE */
80307
80308 /* No fast path for DECLVAR now, it's quite a rare instruction. */
80309 case DUK_OP_DECLVAR_RR:
80310 case DUK_OP_DECLVAR_CR:
80311 case DUK_OP_DECLVAR_RC:
80312 case DUK_OP_DECLVAR_CC: {
80313 duk_activation *act;
80314 duk_small_uint_fast_t a = DUK_DEC_A(ins);
80315 duk_tval *tv1;
80316 duk_hstring *name;
80317 duk_small_uint_t prop_flags;
80318 duk_bool_t is_func_decl;
80319
80320 tv1 = DUK__REGCONSTP_B(ins);
80321 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
80322 name = DUK_TVAL_GET_STRING(tv1);
80323 DUK_ASSERT(name != NULL);
80324
80325 is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
80326
80327 /* XXX: declvar takes an duk_tval pointer, which is awkward and
80328 * should be reworked.
80329 */
80330
80331 /* Compiler is responsible for selecting property flags (configurability,
80332 * writability, etc).
80333 */
80334 prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
80335
80336 if (is_func_decl) {
80337 duk_push_tval(thr, DUK__REGCONSTP_C(ins));
80338 } else {
80339 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
80340 thr->valstack_top++;
80341 }
80342 tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
80343
80344 act = thr->callstack_curr;
80345 if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
80346 if (is_func_decl) {
80347 /* Already declared, update value. */
80348 tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
80349 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
80350 } else {
80351 /* Already declared but no initializer value
80352 * (e.g. 'var xyz;'), no-op.
80353 */
80354 }
80355 }
80356
80357 duk_pop_unsafe(thr);
80358 break;
80359 }
80360
80361#if defined(DUK_USE_REGEXP_SUPPORT)
80362 /* The compiler should never emit DUK_OP_REGEXP if there is no
80363 * regexp support.
80364 */
80365 case DUK_OP_REGEXP_RR:
80366 case DUK_OP_REGEXP_CR:
80367 case DUK_OP_REGEXP_RC:
80368 case DUK_OP_REGEXP_CC: {
80369 /* A -> target register
80370 * B -> bytecode (also contains flags)
80371 * C -> escaped source
80372 */
80373
80374 duk_push_tval(thr, DUK__REGCONSTP_C(ins));
80375 duk_push_tval(thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */
80376 duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
80377 DUK__REPLACE_TOP_A_BREAK();
80378 }
80379#endif /* DUK_USE_REGEXP_SUPPORT */
80380
80381 /* XXX: 'c' is unused, use whole BC, etc. */
80382 case DUK_OP_CSVAR_RR:
80383 case DUK_OP_CSVAR_CR:
80384 case DUK_OP_CSVAR_RC:
80385 case DUK_OP_CSVAR_CC: {
80386 /* The speciality of calling through a variable binding is that the
80387 * 'this' value may be provided by the variable lookup: E5 Section 6.b.i.
80388 *
80389 * The only (standard) case where the 'this' binding is non-null is when
80390 * (1) the variable is found in an object environment record, and
80391 * (2) that object environment record is a 'with' block.
80392 */
80393
80394 duk_activation *act;
80395 duk_uint_fast_t idx;
80396 duk_tval *tv1;
80397 duk_hstring *name;
80398
80399 /* A -> target registers (A, A + 1) for call setup
80400 * B -> identifier name, usually constant but can be a register due to shuffling
80401 */
80402
80403 tv1 = DUK__REGCONSTP_B(ins);
80404 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
80405 name = DUK_TVAL_GET_STRING(tv1);
80406 DUK_ASSERT(name != NULL);
80407 act = thr->callstack_curr;
80408 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
80409
80410 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
80411
80412 /* Could add direct value stack handling. */
80413 duk_replace(thr, (duk_idx_t) (idx + 1)); /* 'this' binding */
80414 duk_replace(thr, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
80415 break;
80416 }
80417
80418 case DUK_OP_CLOSURE: {
80419 duk_activation *act;
80420 duk_hcompfunc *fun_act;
80421 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80422 duk_hobject *fun_temp;
80423
80424 /* A -> target reg
80425 * BC -> inner function index
80426 */
80427
80428 DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
80429 (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
80430
80431 DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
80432 DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
80433
80434 act = thr->callstack_curr;
80435 fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
80436 fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc];
80437 DUK_ASSERT(fun_temp != NULL);
80438 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp));
80439
80440 DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
80441 (void *) fun_temp, (duk_heaphdr *) fun_temp));
80442
80443 if (act->lex_env == NULL) {
80444 DUK_ASSERT(act->var_env == NULL);
80445 duk_js_init_activation_environment_records_delayed(thr, act);
80446 act = thr->callstack_curr;
80447 }
80448 DUK_ASSERT(act->lex_env != NULL);
80449 DUK_ASSERT(act->var_env != NULL);
80450
80451 /* functions always have a NEWENV flag, i.e. they get a
80452 * new variable declaration environment, so only lex_env
80453 * matters here.
80454 */
80455 duk_js_push_closure(thr,
80456 (duk_hcompfunc *) fun_temp,
80457 act->var_env,
80458 act->lex_env,
80459 1 /*add_auto_proto*/);
80460 DUK__REPLACE_TOP_A_BREAK();
80461 }
80462
80463 case DUK_OP_GETVAR: {
80464 duk_activation *act;
80465 duk_tval *tv1;
80466 duk_hstring *name;
80467
80468 tv1 = DUK__CONSTP_BC(ins);
80469 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
80470 name = DUK_TVAL_GET_STRING(tv1);
80471 DUK_ASSERT(name != NULL);
80472 act = thr->callstack_curr;
80473 DUK_ASSERT(act != NULL);
80474 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
80475 duk_pop_unsafe(thr); /* 'this' binding is not needed here */
80476 DUK__REPLACE_TOP_A_BREAK();
80477 }
80478
80479 case DUK_OP_PUTVAR: {
80480 duk_activation *act;
80481 duk_tval *tv1;
80482 duk_hstring *name;
80483
80484 tv1 = DUK__CONSTP_BC(ins);
80485 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
80486 name = DUK_TVAL_GET_STRING(tv1);
80487 DUK_ASSERT(name != NULL);
80488
80489 /* XXX: putvar takes a duk_tval pointer, which is awkward and
80490 * should be reworked.
80491 */
80492
80493 tv1 = DUK__REGP_A(ins); /* val */
80494 act = thr->callstack_curr;
80495 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
80496 break;
80497 }
80498
80499 case DUK_OP_DELVAR: {
80500 duk_activation *act;
80501 duk_tval *tv1;
80502 duk_hstring *name;
80503 duk_bool_t rc;
80504
80505 tv1 = DUK__CONSTP_BC(ins);
80506 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
80507 name = DUK_TVAL_GET_STRING(tv1);
80508 DUK_ASSERT(name != NULL);
80509 act = thr->callstack_curr;
80510 rc = duk_js_delvar_activation(thr, act, name);
80511 DUK__REPLACE_BOOL_A_BREAK(rc);
80512 }
80513
80514 case DUK_OP_JUMP: {
80515 /* Note: without explicit cast to signed, MSVC will
80516 * apparently generate a large positive jump when the
80517 * bias-corrected value would normally be negative.
80518 */
80519 curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS;
80520 break;
80521 }
80522
80523#define DUK__RETURN_SHARED() do { \
80524 duk_small_uint_t ret_result; \
80525 /* duk__handle_return() is guaranteed never to throw, except \
80526 * for potential out-of-memory situations which will then \
80527 * propagate out of the executor longjmp handler. \
80528 */ \
80529 DUK_ASSERT(thr->ptr_curr_pc == NULL); \
80530 ret_result = duk__handle_return(thr, entry_act); \
80531 if (ret_result == DUK__RETHAND_RESTART) { \
80532 goto restart_execution; \
80533 } \
80534 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \
80535 return; \
80536 } while (0)
80537#if defined(DUK_USE_EXEC_PREFER_SIZE)
80538 case DUK_OP_RETREG:
80539 case DUK_OP_RETCONST:
80540 case DUK_OP_RETCONSTN:
80541 case DUK_OP_RETUNDEF: {
80542 /* BC -> return value reg/const */
80543
80544 DUK__SYNC_AND_NULL_CURR_PC();
80545
80546 if (op == DUK_OP_RETREG) {
80547 duk_push_tval(thr, DUK__REGP_BC(ins));
80548 } else if (op == DUK_OP_RETUNDEF) {
80549 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
80550 thr->valstack_top++;
80551 } else {
80552 DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN);
80553 duk_push_tval(thr, DUK__CONSTP_BC(ins));
80554 }
80555
80556 DUK__RETURN_SHARED();
80557 }
80558#else /* DUK_USE_EXEC_PREFER_SIZE */
80559 case DUK_OP_RETREG: {
80560 duk_tval *tv;
80561
80562 DUK__SYNC_AND_NULL_CURR_PC();
80563 tv = DUK__REGP_BC(ins);
80564 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
80565 DUK_TVAL_INCREF(thr, tv);
80566 thr->valstack_top++;
80567 DUK__RETURN_SHARED();
80568 }
80569 /* This will be unused without refcounting. */
80570 case DUK_OP_RETCONST: {
80571 duk_tval *tv;
80572
80573 DUK__SYNC_AND_NULL_CURR_PC();
80574 tv = DUK__CONSTP_BC(ins);
80575 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
80576 DUK_TVAL_INCREF(thr, tv);
80577 thr->valstack_top++;
80578 DUK__RETURN_SHARED();
80579 }
80580 case DUK_OP_RETCONSTN: {
80581 duk_tval *tv;
80582
80583 DUK__SYNC_AND_NULL_CURR_PC();
80584 tv = DUK__CONSTP_BC(ins);
80585 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
80586#if defined(DUK_USE_REFERENCE_COUNTING)
80587 /* Without refcounting only RETCONSTN is used. */
80588 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */
80589#endif
80590 thr->valstack_top++;
80591 DUK__RETURN_SHARED();
80592 }
80593 case DUK_OP_RETUNDEF: {
80594 DUK__SYNC_AND_NULL_CURR_PC();
80595 thr->valstack_top++; /* value at valstack top is already undefined by valstack policy */
80596 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
80597 DUK__RETURN_SHARED();
80598 }
80599#endif /* DUK_USE_EXEC_PREFER_SIZE */
80600
80601 case DUK_OP_LABEL: {
80602 duk_activation *act;
80603 duk_catcher *cat;
80604 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80605
80606 /* Allocate catcher and populate it (must be atomic). */
80607
80608 cat = duk_hthread_catcher_alloc(thr);
80609 DUK_ASSERT(cat != NULL);
80610
80611 cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT));
80612 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
80613 cat->idx_base = 0; /* unused for label */
80614 cat->h_varname = NULL;
80615
80616 act = thr->callstack_curr;
80617 DUK_ASSERT(act != NULL);
80618 cat->parent = act->cat;
80619 act->cat = cat;
80620
80621 DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, "
80622 "idx_base=%ld, h_varname=%!O, label_id=%ld",
80623 (long) cat->flags, (long) cat->pc_base,
80624 (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
80625
80626 curr_pc += 2; /* skip jump slots */
80627 break;
80628 }
80629
80630 case DUK_OP_ENDLABEL: {
80631 duk_activation *act;
80632#if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS)
80633 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80634#endif
80635#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
80636 DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
80637#endif
80638
80639 act = thr->callstack_curr;
80640 DUK_ASSERT(act->cat != NULL);
80641 DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL);
80642 DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc);
80643 duk_hthread_catcher_unwind_nolexenv_norz(thr, act);
80644
80645 /* no need to unwind callstack */
80646 break;
80647 }
80648
80649 case DUK_OP_BREAK: {
80650 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80651
80652 DUK__SYNC_AND_NULL_CURR_PC();
80653 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
80654 goto restart_execution;
80655 }
80656
80657 case DUK_OP_CONTINUE: {
80658 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80659
80660 DUK__SYNC_AND_NULL_CURR_PC();
80661 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
80662 goto restart_execution;
80663 }
80664
80665 /* XXX: move to helper, too large to be inline here */
80666 case DUK_OP_TRYCATCH: {
80667 duk__handle_op_trycatch(thr, ins, curr_pc);
80668 curr_pc += 2; /* skip jump slots */
80669 break;
80670 }
80671
80672 case DUK_OP_ENDTRY: {
80673 curr_pc = duk__handle_op_endtry(thr, ins);
80674 break;
80675 }
80676
80677 case DUK_OP_ENDCATCH: {
80678 duk__handle_op_endcatch(thr, ins);
80679 break;
80680 }
80681
80682 case DUK_OP_ENDFIN: {
80683 /* Sync and NULL early. */
80684 DUK__SYNC_AND_NULL_CURR_PC();
80685
80686 if (duk__handle_op_endfin(thr, ins, entry_act) != 0) {
80687 return;
80688 }
80689
80690 /* Must restart because we NULLed out curr_pc. */
80691 goto restart_execution;
80692 }
80693
80694 case DUK_OP_THROW: {
80695 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80696
80697 /* Note: errors are augmented when they are created, not
80698 * when they are thrown. So, don't augment here, it would
80699 * break re-throwing for instance.
80700 */
80701
80702 /* Sync so that augmentation sees up-to-date activations, NULL
80703 * thr->ptr_curr_pc so that it's not used if side effects occur
80704 * in augmentation or longjmp handling.
80705 */
80706 DUK__SYNC_AND_NULL_CURR_PC();
80707
80708 duk_dup(thr, (duk_idx_t) bc);
80709 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
80710 (duk_tval *) duk_get_tval(thr, -1)));
80711#if defined(DUK_USE_AUGMENT_ERROR_THROW)
80712 duk_err_augment_error_throw(thr);
80713 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
80714 (duk_tval *) duk_get_tval(thr, -1)));
80715#endif
80716
80717 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
80718#if defined(DUK_USE_DEBUGGER_SUPPORT)
80719 duk_err_check_debugger_integration(thr);
80720#endif
80721
80722 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
80723 duk_err_longjmp(thr);
80724 DUK_UNREACHABLE();
80725 break;
80726 }
80727
80728 case DUK_OP_CSREG: {
80729 /*
80730 * Assuming a register binds to a variable declared within this
80731 * function (a declarative binding), the 'this' for the call
80732 * setup is always 'undefined'. E5 Section 10.2.1.1.6.
80733 */
80734
80735 duk_small_uint_fast_t a = DUK_DEC_A(ins);
80736 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
80737
80738 /* A -> register containing target function (not type checked here)
80739 * BC -> target registers (BC, BC + 1) for call setup
80740 */
80741
80742#if defined(DUK_USE_PREFER_SIZE)
80743 duk_dup(thr, (duk_idx_t) a);
80744 duk_replace(thr, (duk_idx_t) bc);
80745 duk_to_undefined(thr, (duk_idx_t) (bc + 1));
80746#else
80747 duk_tval *tv1;
80748 duk_tval *tv2;
80749 duk_tval *tv3;
80750 duk_tval tv_tmp1;
80751 duk_tval tv_tmp2;
80752
80753 tv1 = DUK__REGP(bc);
80754 tv2 = tv1 + 1;
80755 DUK_TVAL_SET_TVAL(&tv_tmp1, tv1);
80756 DUK_TVAL_SET_TVAL(&tv_tmp2, tv2);
80757 tv3 = DUK__REGP(a);
80758 DUK_TVAL_SET_TVAL(tv1, tv3);
80759 DUK_TVAL_INCREF(thr, tv1); /* no side effects */
80760 DUK_TVAL_SET_UNDEFINED(tv2); /* no need for incref */
80761 DUK_TVAL_DECREF(thr, &tv_tmp1);
80762 DUK_TVAL_DECREF(thr, &tv_tmp2);
80763#endif
80764 break;
80765 }
80766
80767
80768 /* XXX: in some cases it's faster NOT to reuse the value
80769 * stack but rather copy the arguments on top of the stack
80770 * (mainly when the calling value stack is large and the value
80771 * stack resize would be large).
80772 */
80773
80774 case DUK_OP_CALL0:
80775 case DUK_OP_CALL1:
80776 case DUK_OP_CALL2:
80777 case DUK_OP_CALL3:
80778 case DUK_OP_CALL4:
80779 case DUK_OP_CALL5:
80780 case DUK_OP_CALL6:
80781 case DUK_OP_CALL7: {
80782 /* Opcode packs 4 flag bits: 1 for indirect, 3 map
80783 * 1:1 to three lowest call handling flags.
80784 *
80785 * A -> nargs or register with nargs (indirect)
80786 * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
80787 */
80788
80789 duk_idx_t nargs;
80790 duk_idx_t idx;
80791 duk_small_uint_t call_flags;
80792#if !defined(DUK_USE_EXEC_FUN_LOCAL)
80793 duk_hcompfunc *fun;
80794#endif
80795
80796 DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
80797 DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0);
80798
80799 nargs = (duk_idx_t) DUK_DEC_A(ins);
80800 call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
80801 idx = (duk_idx_t) DUK_DEC_BC(ins);
80802
80803 if (duk__executor_handle_call(thr, idx, nargs, call_flags)) {
80804 /* curr_pc synced by duk_handle_call_unprotected() */
80805 DUK_ASSERT(thr->ptr_curr_pc == NULL);
80806 goto restart_execution;
80807 }
80808 DUK_ASSERT(thr->ptr_curr_pc != NULL);
80809
80810 /* duk_js_call.c is required to restore the stack reserve
80811 * so we only need to reset the top.
80812 */
80813#if !defined(DUK_USE_EXEC_FUN_LOCAL)
80814 fun = DUK__FUN();
80815#endif
80816 duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
80817
80818 /* No need to reinit setjmp() catchpoint, as call handling
80819 * will store and restore our state.
80820 *
80821 * When debugger is enabled, we need to recheck the activation
80822 * status after returning. This is now handled by call handling
80823 * and heap->dbg_force_restart.
80824 */
80825 break;
80826 }
80827
80828 case DUK_OP_CALL8:
80829 case DUK_OP_CALL9:
80830 case DUK_OP_CALL10:
80831 case DUK_OP_CALL11:
80832 case DUK_OP_CALL12:
80833 case DUK_OP_CALL13:
80834 case DUK_OP_CALL14:
80835 case DUK_OP_CALL15: {
80836 /* Indirect variant. */
80837 duk_uint_fast_t nargs;
80838 duk_idx_t idx;
80839 duk_small_uint_t call_flags;
80840#if !defined(DUK_USE_EXEC_FUN_LOCAL)
80841 duk_hcompfunc *fun;
80842#endif
80843
80844 DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
80845 DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0);
80846
80847 nargs = (duk_uint_fast_t) DUK_DEC_A(ins);
80848 DUK__LOOKUP_INDIRECT(nargs);
80849 call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
80850 idx = (duk_idx_t) DUK_DEC_BC(ins);
80851
80852 if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) {
80853 DUK_ASSERT(thr->ptr_curr_pc == NULL);
80854 goto restart_execution;
80855 }
80856 DUK_ASSERT(thr->ptr_curr_pc != NULL);
80857
80858#if !defined(DUK_USE_EXEC_FUN_LOCAL)
80859 fun = DUK__FUN();
80860#endif
80861 duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
80862 break;
80863 }
80864
80865 case DUK_OP_NEWOBJ: {
80866 duk_push_object(thr);
80867#if defined(DUK_USE_ASSERTIONS)
80868 {
80869 duk_hobject *h;
80870 h = duk_require_hobject(thr, -1);
80871 DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
80872 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
80873 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
80874 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
80875 }
80876#endif
80877#if !defined(DUK_USE_PREFER_SIZE)
80878 /* XXX: could do a direct props realloc, but need hash size */
80879 duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
80880#endif
80881 DUK__REPLACE_TOP_BC_BREAK();
80882 }
80883
80884 case DUK_OP_NEWARR: {
80885 duk_push_array(thr);
80886#if defined(DUK_USE_ASSERTIONS)
80887 {
80888 duk_hobject *h;
80889 h = duk_require_hobject(thr, -1);
80890 DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
80891 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
80892 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
80893 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
80894 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h));
80895 }
80896#endif
80897#if !defined(DUK_USE_PREFER_SIZE)
80898 duk_hobject_realloc_props(thr,
80899 duk_known_hobject(thr, -1),
80900 0 /*new_e_size*/,
80901 DUK_DEC_A(ins) /*new_a_size*/,
80902 0 /*new_h_size*/,
80903 0 /*abandon_array*/);
80904#if 0
80905 duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
80906#endif
80907#endif
80908 DUK__REPLACE_TOP_BC_BREAK();
80909 }
80910
80911 case DUK_OP_MPUTOBJ:
80912 case DUK_OP_MPUTOBJI: {
80913 duk_idx_t obj_idx;
80914 duk_uint_fast_t idx, idx_end;
80915 duk_small_uint_fast_t count;
80916
80917 /* A -> register of target object
80918 * B -> first register of key/value pair list
80919 * or register containing first register number if indirect
80920 * C -> number of key/value pairs * 2
80921 * (= number of value stack indices used starting from 'B')
80922 */
80923
80924 obj_idx = DUK_DEC_A(ins);
80925 DUK_ASSERT(duk_is_object(thr, obj_idx));
80926
80927 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
80928 if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
80929 DUK__LOOKUP_INDIRECT(idx);
80930 }
80931
80932 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
80933 DUK_ASSERT(count > 0); /* compiler guarantees */
80934 idx_end = idx + count;
80935
80936#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
80937 if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) {
80938 /* XXX: use duk_is_valid_index() instead? */
80939 /* XXX: improve check; check against nregs, not against top */
80940 DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
80941 }
80942#endif
80943
80944 /* Use 'force' flag to duk_def_prop() to ensure that any
80945 * inherited properties don't prevent the operation.
80946 * With ES2015 duplicate properties are allowed, so that we
80947 * must overwrite any previous data or accessor property.
80948 *
80949 * With ES2015 computed property names the literal keys
80950 * may be arbitrary values and need to be ToPropertyKey()
80951 * coerced at runtime.
80952 */
80953 do {
80954 /* XXX: faster initialization (direct access or better primitives) */
80955 duk_dup(thr, (duk_idx_t) idx);
80956 duk_dup(thr, (duk_idx_t) (idx + 1));
80957 duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE |
80958 DUK_DEFPROP_FORCE |
80959 DUK_DEFPROP_SET_WRITABLE |
80960 DUK_DEFPROP_SET_ENUMERABLE |
80961 DUK_DEFPROP_SET_CONFIGURABLE);
80962 idx += 2;
80963 } while (idx < idx_end);
80964 break;
80965 }
80966
80967 case DUK_OP_INITSET:
80968 case DUK_OP_INITGET: {
80969 duk__handle_op_initset_initget(thr, ins);
80970 break;
80971 }
80972
80973 case DUK_OP_MPUTARR:
80974 case DUK_OP_MPUTARRI: {
80975 duk_idx_t obj_idx;
80976 duk_uint_fast_t idx, idx_end;
80977 duk_small_uint_fast_t count;
80978 duk_tval *tv1;
80979 duk_uint32_t arr_idx;
80980
80981 /* A -> register of target object
80982 * B -> first register of value data (start_index, value1, value2, ..., valueN)
80983 * or register containing first register number if indirect
80984 * C -> number of key/value pairs (N)
80985 */
80986
80987 obj_idx = DUK_DEC_A(ins);
80988 DUK_ASSERT(duk_is_object(thr, obj_idx));
80989
80990 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
80991 if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
80992 DUK__LOOKUP_INDIRECT(idx);
80993 }
80994
80995 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
80996 DUK_ASSERT(count > 0 + 1); /* compiler guarantees */
80997 idx_end = idx + count;
80998
80999#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
81000 if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) {
81001 /* XXX: use duk_is_valid_index() instead? */
81002 /* XXX: improve check; check against nregs, not against top */
81003 DUK__INTERNAL_ERROR("MPUTARR out of bounds");
81004 }
81005#endif
81006
81007 tv1 = DUK__REGP(idx);
81008 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
81009#if defined(DUK_USE_FASTINT)
81010 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
81011 arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
81012#else
81013 arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
81014#endif
81015 idx++;
81016
81017 do {
81018 /* duk_xdef_prop() will define an own property without any array
81019 * special behaviors. We'll need to set the array length explicitly
81020 * in the end. For arrays with elisions, the compiler will emit an
81021 * explicit SETALEN which will update the length.
81022 */
81023
81024 /* XXX: because we're dealing with 'own' properties of a fresh array,
81025 * the array initializer should just ensure that the array has a large
81026 * enough array part and write the values directly into array part,
81027 * and finally set 'length' manually in the end (as already happens now).
81028 */
81029
81030 duk_dup(thr, (duk_idx_t) idx);
81031 duk_xdef_prop_index_wec(thr, obj_idx, arr_idx);
81032
81033 idx++;
81034 arr_idx++;
81035 } while (idx < idx_end);
81036
81037 /* XXX: E5.1 Section 11.1.4 coerces the final length through
81038 * ToUint32() which is odd but happens now as a side effect of
81039 * 'arr_idx' type.
81040 */
81041 duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx);
81042 break;
81043 }
81044
81045 case DUK_OP_SETALEN: {
81046 duk_tval *tv1;
81047 duk_hobject *h;
81048 duk_uint32_t len;
81049
81050 tv1 = DUK__REGP_A(ins);
81051 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
81052 h = DUK_TVAL_GET_OBJECT(tv1);
81053 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h));
81054
81055 tv1 = DUK__REGP_BC(ins);
81056 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
81057#if defined(DUK_USE_FASTINT)
81058 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
81059 len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
81060#else
81061 len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
81062#endif
81063 ((duk_harray *) h)->length = len;
81064 break;
81065 }
81066
81067 case DUK_OP_INITENUM: {
81068 duk__handle_op_initenum(thr, ins);
81069 break;
81070 }
81071
81072 case DUK_OP_NEXTENUM: {
81073 curr_pc += duk__handle_op_nextenum(thr, ins);
81074 break;
81075 }
81076
81077 case DUK_OP_INVLHS: {
81078 DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE);
81079 DUK_WO_NORETURN(return;);
81080 break;
81081 }
81082
81083 case DUK_OP_DEBUGGER: {
81084 /* Opcode only emitted by compiler when debugger
81085 * support is enabled. Ignore it silently without
81086 * debugger support, in case it has been loaded
81087 * from precompiled bytecode.
81088 */
81089#if defined(DUK_USE_DEBUGGER_SUPPORT)
81090 if (duk_debug_is_attached(thr->heap)) {
81091 DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
81092 DUK__SYNC_AND_NULL_CURR_PC();
81093 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
81094 DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
81095 goto restart_execution;
81096 } else {
81097 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
81098 }
81099#else
81100 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
81101#endif
81102 break;
81103 }
81104
81105 case DUK_OP_NOP: {
81106 /* Nop, ignored, but ABC fields may carry a value e.g.
81107 * for indirect opcode handling.
81108 */
81109 break;
81110 }
81111
81112 case DUK_OP_INVALID: {
81113 DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins));
81114 DUK_WO_NORETURN(return;);
81115 break;
81116 }
81117
81118#if defined(DUK_USE_ES6)
81119 case DUK_OP_NEWTARGET: {
81120 duk_push_new_target(thr);
81121 DUK__REPLACE_TOP_BC_BREAK();
81122 }
81123#endif /* DUK_USE_ES6 */
81124
81125#if !defined(DUK_USE_EXEC_PREFER_SIZE)
81126#if !defined(DUK_USE_ES7_EXP_OPERATOR)
81127 case DUK_OP_EXP_RR:
81128 case DUK_OP_EXP_CR:
81129 case DUK_OP_EXP_RC:
81130 case DUK_OP_EXP_CC:
81131#endif
81132#if !defined(DUK_USE_ES6)
81133 case DUK_OP_NEWTARGET:
81134#endif
81135#if !defined(DUK_USE_VERBOSE_ERRORS)
81136 case DUK_OP_GETPROPC_RR:
81137 case DUK_OP_GETPROPC_CR:
81138 case DUK_OP_GETPROPC_RC:
81139 case DUK_OP_GETPROPC_CC:
81140#endif
81141 case DUK_OP_UNUSED207:
81142 case DUK_OP_UNUSED212:
81143 case DUK_OP_UNUSED213:
81144 case DUK_OP_UNUSED214:
81145 case DUK_OP_UNUSED215:
81146 case DUK_OP_UNUSED216:
81147 case DUK_OP_UNUSED217:
81148 case DUK_OP_UNUSED218:
81149 case DUK_OP_UNUSED219:
81150 case DUK_OP_UNUSED220:
81151 case DUK_OP_UNUSED221:
81152 case DUK_OP_UNUSED222:
81153 case DUK_OP_UNUSED223:
81154 case DUK_OP_UNUSED224:
81155 case DUK_OP_UNUSED225:
81156 case DUK_OP_UNUSED226:
81157 case DUK_OP_UNUSED227:
81158 case DUK_OP_UNUSED228:
81159 case DUK_OP_UNUSED229:
81160 case DUK_OP_UNUSED230:
81161 case DUK_OP_UNUSED231:
81162 case DUK_OP_UNUSED232:
81163 case DUK_OP_UNUSED233:
81164 case DUK_OP_UNUSED234:
81165 case DUK_OP_UNUSED235:
81166 case DUK_OP_UNUSED236:
81167 case DUK_OP_UNUSED237:
81168 case DUK_OP_UNUSED238:
81169 case DUK_OP_UNUSED239:
81170 case DUK_OP_UNUSED240:
81171 case DUK_OP_UNUSED241:
81172 case DUK_OP_UNUSED242:
81173 case DUK_OP_UNUSED243:
81174 case DUK_OP_UNUSED244:
81175 case DUK_OP_UNUSED245:
81176 case DUK_OP_UNUSED246:
81177 case DUK_OP_UNUSED247:
81178 case DUK_OP_UNUSED248:
81179 case DUK_OP_UNUSED249:
81180 case DUK_OP_UNUSED250:
81181 case DUK_OP_UNUSED251:
81182 case DUK_OP_UNUSED252:
81183 case DUK_OP_UNUSED253:
81184 case DUK_OP_UNUSED254:
81185 case DUK_OP_UNUSED255:
81186 /* Force all case clauses to map to an actual handler
81187 * so that the compiler can emit a jump without a bounds
81188 * check: the switch argument is a duk_uint8_t so that
81189 * the compiler may be able to figure it out. This is
81190 * a small detail and obviously compiler dependent.
81191 */
81192 /* default: clause omitted on purpose */
81193#else /* DUK_USE_EXEC_PREFER_SIZE */
81194 default:
81195#endif /* DUK_USE_EXEC_PREFER_SIZE */
81196 {
81197 /* Default case catches invalid/unsupported opcodes. */
81198 DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins));
81199 DUK__INTERNAL_ERROR("invalid opcode");
81200 break;
81201 }
81202
81203 } /* end switch */
81204
81205 continue;
81206
81207 /* Some shared exit paths for opcode handling below. These
81208 * are mostly useful to reduce code footprint when multiple
81209 * opcodes have a similar epilogue (like replacing stack top
81210 * with index 'a').
81211 */
81212
81213#if defined(DUK_USE_EXEC_PREFER_SIZE)
81214 replace_top_a:
81215 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins));
81216 continue;
81217 replace_top_bc:
81218 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins));
81219 continue;
81220#endif
81221 }
81222 DUK_WO_NORETURN(return;);
81223
81224#if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
81225 internal_error:
81226 DUK_ERROR_INTERNAL(thr);
81227 DUK_WO_NORETURN(return;);
81228#endif
81229}
81230
81231/* automatic undefs */
81232#undef DUK__BYTEOFF_A
81233#undef DUK__BYTEOFF_B
81234#undef DUK__BYTEOFF_BC
81235#undef DUK__BYTEOFF_C
81236#undef DUK__COMPARE_BODY
81237#undef DUK__CONST
81238#undef DUK__CONSTP
81239#undef DUK__CONSTP_A
81240#undef DUK__CONSTP_B
81241#undef DUK__CONSTP_BC
81242#undef DUK__CONSTP_C
81243#undef DUK__DELPROP_BODY
81244#undef DUK__EQ_BODY
81245#undef DUK__FUN
81246#undef DUK__GETPROPC_BODY
81247#undef DUK__GETPROP_BODY
81248#undef DUK__GE_BODY
81249#undef DUK__GT_BODY
81250#undef DUK__INSTOF_BODY
81251#undef DUK__INTERNAL_ERROR
81252#undef DUK__INT_NOACTION
81253#undef DUK__INT_RESTART
81254#undef DUK__IN_BODY
81255#undef DUK__LE_BODY
81256#undef DUK__LONGJMP_RESTART
81257#undef DUK__LONGJMP_RETHROW
81258#undef DUK__LOOKUP_INDIRECT
81259#undef DUK__LT_BODY
81260#undef DUK__MASK_A
81261#undef DUK__MASK_B
81262#undef DUK__MASK_BC
81263#undef DUK__MASK_C
81264#undef DUK__NEQ_BODY
81265#undef DUK__PUTPROP_BODY
81266#undef DUK__RCBIT_B
81267#undef DUK__RCBIT_C
81268#undef DUK__REG
81269#undef DUK__REGCONSTP_B
81270#undef DUK__REGCONSTP_C
81271#undef DUK__REGP
81272#undef DUK__REGP_A
81273#undef DUK__REGP_B
81274#undef DUK__REGP_BC
81275#undef DUK__REGP_C
81276#undef DUK__REPLACE_BOOL_A_BREAK
81277#undef DUK__REPLACE_TOP_A_BREAK
81278#undef DUK__REPLACE_TOP_BC_BREAK
81279#undef DUK__REPLACE_TO_TVPTR
81280#undef DUK__RETHAND_FINISHED
81281#undef DUK__RETHAND_RESTART
81282#undef DUK__RETURN_SHARED
81283#undef DUK__SEQ_BODY
81284#undef DUK__SHIFT_A
81285#undef DUK__SHIFT_B
81286#undef DUK__SHIFT_BC
81287#undef DUK__SHIFT_C
81288#undef DUK__SNEQ_BODY
81289#undef DUK__STRICT
81290#undef DUK__SYNC_AND_NULL_CURR_PC
81291#undef DUK__SYNC_CURR_PC
81292#undef DUK__TVAL_SHIFT
81293#line 1 "duk_js_ops.c"
81294/*
81295 * ECMAScript specification algorithm and conversion helpers.
81296 *
81297 * These helpers encapsulate the primitive ECMAScript operation semantics,
81298 * and are used by the bytecode executor and the API (among other places).
81299 * Some primitives are only implemented as part of the API and have no
81300 * "internal" helper. This is the case when an internal helper would not
81301 * really be useful; e.g. the operation is rare, uses value stack heavily,
81302 * etc.
81303 *
81304 * The operation arguments depend on what is required to implement
81305 * the operation:
81306 *
81307 * - If an operation is simple and stateless, and has no side
81308 * effects, it won't take an duk_hthread argument and its
81309 * arguments may be duk_tval pointers (which are safe as long
81310 * as no side effects take place).
81311 *
81312 * - If complex coercions are required (e.g. a "ToNumber" coercion)
81313 * or errors may be thrown, the operation takes an duk_hthread
81314 * argument. This also implies that the operation may have
81315 * arbitrary side effects, invalidating any duk_tval pointers.
81316 *
81317 * - For operations with potential side effects, arguments can be
81318 * taken in several ways:
81319 *
81320 * a) as duk_tval pointers, which makes sense if the "common case"
81321 * can be resolved without side effects (e.g. coercion); the
81322 * arguments are pushed to the valstack for coercion if
81323 * necessary
81324 *
81325 * b) as duk_tval values
81326 *
81327 * c) implicitly on value stack top
81328 *
81329 * d) as indices to the value stack
81330 *
81331 * Future work:
81332 *
81333 * - Argument styles may not be the most sensible in every case now.
81334 *
81335 * - In-place coercions might be useful for several operations, if
81336 * in-place coercion is OK for the bytecode executor and the API.
81337 */
81338
81339/* #include duk_internal.h -> already included */
81340
81341/*
81342 * ToPrimitive() (E5 Section 9.1)
81343 *
81344 * ==> implemented in the API.
81345 */
81346
81347/*
81348 * ToBoolean() (E5 Section 9.2)
81349 */
81350
81351DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
81352 switch (DUK_TVAL_GET_TAG(tv)) {
81353 case DUK_TAG_UNDEFINED:
81354 case DUK_TAG_NULL:
81355 return 0;
81356 case DUK_TAG_BOOLEAN:
81357 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1);
81358 return DUK_TVAL_GET_BOOLEAN(tv);
81359 case DUK_TAG_STRING: {
81360 /* Symbols ToBoolean() coerce to true, regardless of their
81361 * description. This happens with no explicit check because
81362 * of the symbol representation byte prefix.
81363 */
81364 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
81365 DUK_ASSERT(h != NULL);
81366 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
81367 }
81368 case DUK_TAG_OBJECT: {
81369 return 1;
81370 }
81371 case DUK_TAG_BUFFER: {
81372 /* Mimic Uint8Array semantics: objects coerce true, regardless
81373 * of buffer length (zero or not) or context.
81374 */
81375 return 1;
81376 }
81377 case DUK_TAG_POINTER: {
81378 void *p = DUK_TVAL_GET_POINTER(tv);
81379 return (p != NULL ? 1 : 0);
81380 }
81381 case DUK_TAG_LIGHTFUNC: {
81382 return 1;
81383 }
81384#if defined(DUK_USE_FASTINT)
81385 case DUK_TAG_FASTINT:
81386 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
81387 return 1;
81388 } else {
81389 return 0;
81390 }
81391#endif
81392 default: {
81393 /* number */
81394 duk_double_t d;
81395#if defined(DUK_USE_PREFER_SIZE)
81396 int c;
81397#endif
81398 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
81399 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
81400 d = DUK_TVAL_GET_DOUBLE(tv);
81401#if defined(DUK_USE_PREFER_SIZE)
81402 c = DUK_FPCLASSIFY((double) d);
81403 if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
81404 return 0;
81405 } else {
81406 return 1;
81407 }
81408#else
81409 DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1);
81410 return duk_double_is_nan_or_zero(d) ^ 1;
81411#endif
81412 }
81413 }
81414 DUK_UNREACHABLE();
81415 DUK_WO_UNREACHABLE(return 0;);
81416}
81417
81418/*
81419 * ToNumber() (E5 Section 9.3)
81420 *
81421 * Value to convert must be on stack top, and is popped before exit.
81422 *
81423 * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
81424 * http://www.cs.indiana.edu/~burger/fp/index.html
81425 *
81426 * Notes on the conversion:
81427 *
81428 * - There are specific requirements on the accuracy of the conversion
81429 * through a "Mathematical Value" (MV), so this conversion is not
81430 * trivial.
81431 *
81432 * - Quick rejects (e.g. based on first char) are difficult because
81433 * the grammar allows leading and trailing white space.
81434 *
81435 * - Quick reject based on string length is difficult even after
81436 * accounting for white space; there may be arbitrarily many
81437 * decimal digits.
81438 *
81439 * - Standard grammar allows decimal values ("123"), hex values
81440 * ("0x123") and infinities
81441 *
81442 * - Unlike source code literals, ToNumber() coerces empty strings
81443 * and strings with only whitespace to zero (not NaN). However,
81444 * while '' coerces to 0, '+' and '-' coerce to NaN.
81445 */
81446
81447/* E5 Section 9.3.1 */
81448DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
81449 duk_small_uint_t s2n_flags;
81450 duk_double_t d;
81451
81452 DUK_ASSERT(duk_is_string(thr, -1));
81453
81454 /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
81455 * garbage.
81456 */
81457 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
81458 DUK_S2N_FLAG_ALLOW_EXP |
81459 DUK_S2N_FLAG_ALLOW_PLUS |
81460 DUK_S2N_FLAG_ALLOW_MINUS |
81461 DUK_S2N_FLAG_ALLOW_INF |
81462 DUK_S2N_FLAG_ALLOW_FRAC |
81463 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
81464 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
81465 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
81466 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
81467 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT |
81468 DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT |
81469 DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT;
81470
81471 duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
81472
81473#if defined(DUK_USE_PREFER_SIZE)
81474 d = duk_get_number(thr, -1);
81475 duk_pop_unsafe(thr);
81476#else
81477 thr->valstack_top--;
81478 DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top));
81479 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top)); /* no fastint conversion in numconv now */
81480 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top));
81481 d = DUK_TVAL_GET_DOUBLE(thr->valstack_top); /* assumes not a fastint */
81482 DUK_TVAL_SET_UNDEFINED(thr->valstack_top);
81483#endif
81484
81485 return d;
81486}
81487
81488DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
81489 DUK_ASSERT(thr != NULL);
81490 DUK_ASSERT(tv != NULL);
81491
81492 switch (DUK_TVAL_GET_TAG(tv)) {
81493 case DUK_TAG_UNDEFINED: {
81494 /* return a specific NaN (although not strictly necessary) */
81495 duk_double_union du;
81496 DUK_DBLUNION_SET_NAN(&du);
81497 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
81498 return du.d;
81499 }
81500 case DUK_TAG_NULL: {
81501 /* +0.0 */
81502 return 0.0;
81503 }
81504 case DUK_TAG_BOOLEAN: {
81505 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
81506 return 1.0;
81507 }
81508 return 0.0;
81509 }
81510 case DUK_TAG_STRING: {
81511 /* For Symbols ToNumber() is always a TypeError. */
81512 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
81513 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
81514 DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL);
81515 DUK_WO_NORETURN(return 0.0;);
81516 }
81517 duk_push_hstring(thr, h);
81518 return duk__tonumber_string_raw(thr);
81519 }
81520 case DUK_TAG_BUFFER: /* plain buffer treated like object */
81521 case DUK_TAG_OBJECT: {
81522 duk_double_t d;
81523 duk_push_tval(thr, tv);
81524 duk_to_primitive(thr, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
81525
81526 /* recursive call for a primitive value (guaranteed not to cause second
81527 * recursion).
81528 */
81529 DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
81530 d = duk_js_tonumber(thr, duk_get_tval(thr, -1));
81531
81532 duk_pop_unsafe(thr);
81533 return d;
81534 }
81535 case DUK_TAG_POINTER: {
81536 /* Coerce like boolean */
81537 void *p = DUK_TVAL_GET_POINTER(tv);
81538 return (p != NULL ? 1.0 : 0.0);
81539 }
81540 case DUK_TAG_LIGHTFUNC: {
81541 /* +(function(){}) -> NaN */
81542 return DUK_DOUBLE_NAN;
81543 }
81544#if defined(DUK_USE_FASTINT)
81545 case DUK_TAG_FASTINT:
81546 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
81547#endif
81548 default: {
81549 /* number */
81550 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
81551 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
81552 return DUK_TVAL_GET_DOUBLE(tv);
81553 }
81554 }
81555
81556 DUK_UNREACHABLE();
81557 DUK_WO_UNREACHABLE(return 0.0;);
81558}
81559
81560/*
81561 * ToInteger() (E5 Section 9.4)
81562 */
81563
81564/* exposed, used by e.g. duk_bi_date.c */
81565DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
81566#if defined(DUK_USE_PREFER_SIZE)
81567 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
81568
81569 if (DUK_UNLIKELY(c == DUK_FP_NAN)) {
81570 return 0.0;
81571 } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) {
81572 return x;
81573 } else {
81574 /* Finite, including neg/pos zero. Neg zero sign must be
81575 * preserved.
81576 */
81577 return duk_double_trunc_towards_zero(x);
81578 }
81579#else /* DUK_USE_PREFER_SIZE */
81580 /* NaN and Infinity have the same exponent so it's a cheap
81581 * initial check for the rare path.
81582 */
81583 if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) {
81584 if (duk_double_is_nan(x)) {
81585 return 0.0;
81586 } else {
81587 return x;
81588 }
81589 } else {
81590 return duk_double_trunc_towards_zero(x);
81591 }
81592#endif /* DUK_USE_PREFER_SIZE */
81593}
81594
81595DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
81596 /* XXX: fastint */
81597 duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */
81598 return duk_js_tointeger_number(d);
81599}
81600
81601/*
81602 * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7)
81603 */
81604
81605/* combined algorithm matching E5 Sections 9.5 and 9.6 */
81606DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
81607#if defined (DUK_USE_PREFER_SIZE)
81608 duk_small_int_t c;
81609#endif
81610
81611#if defined (DUK_USE_PREFER_SIZE)
81612 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
81613 if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
81614 return 0.0;
81615 }
81616#else
81617 if (duk_double_is_nan_zero_inf(x)) {
81618 return 0.0;
81619 }
81620#endif
81621
81622 /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
81623 x = duk_double_trunc_towards_zero(x);
81624
81625 /* NOTE: fmod(x) result sign is same as sign of x, which
81626 * differs from what Javascript wants (see Section 9.6).
81627 */
81628
81629 x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */
81630
81631 if (x < 0.0) {
81632 x += DUK_DOUBLE_2TO32;
81633 }
81634 DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32); /* -> x in [0, 2**32[ */
81635
81636 if (is_toint32) {
81637 if (x >= DUK_DOUBLE_2TO31) {
81638 /* x in [2**31, 2**32[ */
81639
81640 x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
81641 }
81642 }
81643
81644 return x;
81645}
81646
81647DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
81648 duk_double_t d;
81649
81650#if defined(DUK_USE_FASTINT)
81651 if (DUK_TVAL_IS_FASTINT(tv)) {
81652 return DUK_TVAL_GET_FASTINT_I32(tv);
81653 }
81654#endif
81655
81656 d = duk_js_tonumber(thr, tv); /* invalidates tv */
81657 d = duk__toint32_touint32_helper(d, 1);
81658 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
81659 DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
81660 DUK_ASSERT(duk_double_equals(d, (duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
81661 return (duk_int32_t) d;
81662}
81663
81664
81665DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
81666 duk_double_t d;
81667
81668#if defined(DUK_USE_FASTINT)
81669 if (DUK_TVAL_IS_FASTINT(tv)) {
81670 return DUK_TVAL_GET_FASTINT_U32(tv);
81671 }
81672#endif
81673
81674 d = duk_js_tonumber(thr, tv); /* invalidates tv */
81675 d = duk__toint32_touint32_helper(d, 0);
81676 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
81677 DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */
81678 DUK_ASSERT(duk_double_equals(d, (duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */
81679 return (duk_uint32_t) d;
81680
81681}
81682
81683DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
81684 /* should be a safe way to compute this */
81685 return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
81686}
81687
81688/*
81689 * ToString() (E5 Section 9.8)
81690 * ToObject() (E5 Section 9.9)
81691 * CheckObjectCoercible() (E5 Section 9.10)
81692 * IsCallable() (E5 Section 9.11)
81693 *
81694 * ==> implemented in the API.
81695 */
81696
81697/*
81698 * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
81699 * 9.12). These have much in common so they can share some helpers.
81700 *
81701 * Future work notes:
81702 *
81703 * - Current implementation (and spec definition) has recursion; this should
81704 * be fixed if possible.
81705 *
81706 * - String-to-number coercion should be possible without going through the
81707 * value stack (and be more compact) if a shared helper is invoked.
81708 */
81709
81710/* Note that this is the same operation for strict and loose equality:
81711 * - E5 Section 11.9.3, step 1.c (loose)
81712 * - E5 Section 11.9.6, step 4 (strict)
81713 */
81714
81715DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
81716#if defined(DUK_USE_PARANOID_MATH)
81717 /* Straightforward algorithm, makes fewer compiler assumptions. */
81718 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
81719 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
81720 if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
81721 return 0;
81722 }
81723 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
81724 return 1;
81725 }
81726 if (x == y) {
81727 return 1;
81728 }
81729 return 0;
81730#else /* DUK_USE_PARANOID_MATH */
81731 /* Better equivalent algorithm. If the compiler is compliant, C and
81732 * ECMAScript semantics are identical for this particular comparison.
81733 * In particular, NaNs must never compare equal and zeroes must compare
81734 * equal regardless of sign. Could also use a macro, but this inlines
81735 * already nicely (no difference on gcc, for instance).
81736 */
81737 if (duk_double_equals(x, y)) {
81738 /* IEEE requires that NaNs compare false */
81739 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
81740 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
81741 return 1;
81742 } else {
81743 /* IEEE requires that zeros compare the same regardless
81744 * of their signed, so if both x and y are zeroes, they
81745 * are caught above.
81746 */
81747 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
81748 return 0;
81749 }
81750#endif /* DUK_USE_PARANOID_MATH */
81751}
81752
81753DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
81754#if defined(DUK_USE_PARANOID_MATH)
81755 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
81756 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
81757
81758 if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
81759 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
81760 return 1;
81761 }
81762 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
81763 /* Note: cannot assume that a non-zero return value of signbit() would
81764 * always be the same -- hence cannot (portably) use something like:
81765 *
81766 * signbit(x) == signbit(y)
81767 */
81768 duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0;
81769 duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0;
81770 return (sx == sy);
81771 }
81772
81773 /* normal comparison; known:
81774 * - both x and y are not NaNs (but one of them can be)
81775 * - both x and y are not zero (but one of them can be)
81776 * - x and y may be denormal or infinite
81777 */
81778
81779 return (x == y);
81780#else /* DUK_USE_PARANOID_MATH */
81781 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
81782 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
81783
81784 if (duk_double_equals(x, y)) {
81785 /* IEEE requires that NaNs compare false */
81786 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
81787 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
81788
81789 /* Using classification has smaller footprint than direct comparison. */
81790 if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
81791 /* Note: cannot assume that a non-zero return value of signbit() would
81792 * always be the same -- hence cannot (portably) use something like:
81793 *
81794 * signbit(x) == signbit(y)
81795 */
81796 return duk_double_same_sign(x, y);
81797 }
81798 return 1;
81799 } else {
81800 /* IEEE requires that zeros compare the same regardless
81801 * of their sign, so if both x and y are zeroes, they
81802 * are caught above.
81803 */
81804 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
81805
81806 /* Difference to non-strict/strict comparison is that NaNs compare
81807 * equal and signed zero signs matter.
81808 */
81809 if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
81810 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
81811 return 1;
81812 }
81813 return 0;
81814 }
81815#endif /* DUK_USE_PARANOID_MATH */
81816}
81817
81818DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
81819 duk_uint_t type_mask_x;
81820 duk_uint_t type_mask_y;
81821
81822 /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
81823 * equals comparison it must be != NULL.
81824 */
81825 DUK_ASSERT(flags != 0 || thr != NULL);
81826
81827 /*
81828 * Same type?
81829 *
81830 * Note: since number values have no explicit tag in the 8-byte
81831 * representation, need the awkward if + switch.
81832 */
81833
81834#if defined(DUK_USE_FASTINT)
81835 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
81836 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
81837 return 1;
81838 } else {
81839 return 0;
81840 }
81841 }
81842 else
81843#endif
81844 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
81845 duk_double_t d1, d2;
81846
81847 /* Catches both doubles and cases where only one argument is
81848 * a fastint so can't assume a double.
81849 */
81850 d1 = DUK_TVAL_GET_NUMBER(tv_x);
81851 d2 = DUK_TVAL_GET_NUMBER(tv_y);
81852 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
81853 /* SameValue */
81854 return duk__js_samevalue_number(d1, d2);
81855 } else {
81856 /* equals and strict equals */
81857 return duk__js_equals_number(d1, d2);
81858 }
81859 } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
81860 switch (DUK_TVAL_GET_TAG(tv_x)) {
81861 case DUK_TAG_UNDEFINED:
81862 case DUK_TAG_NULL: {
81863 return 1;
81864 }
81865 case DUK_TAG_BOOLEAN: {
81866 return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
81867 }
81868 case DUK_TAG_POINTER: {
81869 return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
81870 }
81871 case DUK_TAG_STRING:
81872 case DUK_TAG_OBJECT: {
81873 /* Heap pointer comparison suffices for strings and objects.
81874 * Symbols compare equal if they have the same internal
81875 * representation; again heap pointer comparison suffices.
81876 */
81877 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
81878 }
81879 case DUK_TAG_BUFFER: {
81880 /* In Duktape 2.x plain buffers mimic Uint8Array objects
81881 * so always compare by heap pointer. In Duktape 1.x
81882 * strict comparison would compare heap pointers and
81883 * non-strict would compare contents.
81884 */
81885 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
81886 }
81887 case DUK_TAG_LIGHTFUNC: {
81888 /* At least 'magic' has a significant impact on function
81889 * identity.
81890 */
81891 duk_small_uint_t lf_flags_x;
81892 duk_small_uint_t lf_flags_y;
81893 duk_c_function func_x;
81894 duk_c_function func_y;
81895
81896 DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
81897 DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
81898 return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
81899 }
81900#if defined(DUK_USE_FASTINT)
81901 case DUK_TAG_FASTINT:
81902#endif
81903 default: {
81904 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
81905 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
81906 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
81907 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
81908 DUK_UNREACHABLE();
81909 DUK_WO_UNREACHABLE(return 0;);
81910 }
81911 }
81912 }
81913
81914 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
81915 return 0;
81916 }
81917
81918 DUK_ASSERT(flags == 0); /* non-strict equality from here on */
81919
81920 /*
81921 * Types are different; various cases for non-strict comparison
81922 *
81923 * Since comparison is symmetric, we use a "swap trick" to reduce
81924 * code size.
81925 */
81926
81927 type_mask_x = duk_get_type_mask_tval(tv_x);
81928 type_mask_y = duk_get_type_mask_tval(tv_y);
81929
81930 /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
81931 if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) &&
81932 (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) {
81933 return 1;
81934 }
81935
81936 /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
81937 if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) {
81938 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) {
81939 duk_double_t d1, d2;
81940 d1 = DUK_TVAL_GET_NUMBER(tv_x);
81941 d2 = duk_to_number_tval(thr, tv_y);
81942 return duk__js_equals_number(d1, d2);
81943 }
81944 }
81945 if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) {
81946 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) {
81947 duk_double_t d1, d2;
81948 d1 = DUK_TVAL_GET_NUMBER(tv_y);
81949 d2 = duk_to_number_tval(thr, tv_x);
81950 return duk__js_equals_number(d1, d2);
81951 }
81952 }
81953
81954 /* Boolean/any -> coerce boolean to number and try again. If boolean is
81955 * compared to a pointer, the final comparison after coercion now always
81956 * yields false (as pointer vs. number compares to false), but this is
81957 * not special cased.
81958 *
81959 * ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1.
81960 */
81961 if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) {
81962 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1);
81963 duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x));
81964 duk_push_tval(thr, tv_y);
81965 goto recursive_call;
81966 }
81967 if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) {
81968 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
81969 duk_push_tval(thr, tv_x);
81970 duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y));
81971 goto recursive_call;
81972 }
81973
81974 /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */
81975 if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) &&
81976 (type_mask_y & DUK_TYPE_MASK_OBJECT)) {
81977 /* No symbol check needed because symbols and strings are accepted. */
81978 duk_push_tval(thr, tv_x);
81979 duk_push_tval(thr, tv_y);
81980 duk_to_primitive(thr, -1, DUK_HINT_NONE); /* apparently no hint? */
81981 goto recursive_call;
81982 }
81983 if ((type_mask_x & DUK_TYPE_MASK_OBJECT) &&
81984 (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) {
81985 /* No symbol check needed because symbols and strings are accepted. */
81986 duk_push_tval(thr, tv_x);
81987 duk_push_tval(thr, tv_y);
81988 duk_to_primitive(thr, -2, DUK_HINT_NONE); /* apparently no hint? */
81989 goto recursive_call;
81990 }
81991
81992 /* Nothing worked -> not equal. */
81993 return 0;
81994
81995 recursive_call:
81996 /* Shared code path to call the helper again with arguments on stack top. */
81997 {
81998 duk_bool_t rc;
81999 rc = duk_js_equals_helper(thr,
82000 DUK_GET_TVAL_NEGIDX(thr, -2),
82001 DUK_GET_TVAL_NEGIDX(thr, -1),
82002 0 /*flags:nonstrict*/);
82003 duk_pop_2_unsafe(thr);
82004 return rc;
82005 }
82006}
82007
82008/*
82009 * Comparisons (x >= y, x > y, x <= y, x < y)
82010 *
82011 * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
82012 * flags to get the rest.
82013 */
82014
82015/* XXX: this should probably just operate on the stack top, because it
82016 * needs to push stuff on the stack anyway...
82017 */
82018
82019DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2) {
82020 duk_size_t prefix_len;
82021 duk_small_int_t rc;
82022
82023 prefix_len = (len1 <= len2 ? len1 : len2);
82024
82025 /* duk_memcmp() is guaranteed to return zero (equal) for zero length
82026 * inputs.
82027 */
82028 rc = duk_memcmp_unsafe((const void *) buf1,
82029 (const void *) buf2,
82030 (size_t) prefix_len);
82031
82032 if (rc < 0) {
82033 return -1;
82034 } else if (rc > 0) {
82035 return 1;
82036 }
82037
82038 /* prefix matches, lengths matter now */
82039 if (len1 < len2) {
82040 /* e.g. "x" < "xx" */
82041 return -1;
82042 } else if (len1 > len2) {
82043 return 1;
82044 }
82045
82046 return 0;
82047}
82048
82049DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
82050 /*
82051 * String comparison (E5 Section 11.8.5, step 4), which
82052 * needs to compare codepoint by codepoint.
82053 *
82054 * However, UTF-8 allows us to use strcmp directly: the shared
82055 * prefix will be encoded identically (UTF-8 has unique encoding)
82056 * and the first differing character can be compared with a simple
82057 * unsigned byte comparison (which strcmp does).
82058 *
82059 * This will not work properly for non-xutf-8 strings, but this
82060 * is not an issue for compliance.
82061 */
82062
82063 DUK_ASSERT(h1 != NULL);
82064 DUK_ASSERT(h2 != NULL);
82065
82066 return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
82067 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
82068 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
82069 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
82070}
82071
82072#if 0 /* unused */
82073DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
82074 /* Similar to String comparison. */
82075
82076 DUK_ASSERT(h1 != NULL);
82077 DUK_ASSERT(h2 != NULL);
82078 DUK_UNREF(heap);
82079
82080 return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
82081 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
82082 (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
82083 (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
82084}
82085#endif
82086
82087#if defined(DUK_USE_FASTINT)
82088DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) {
82089 DUK_ASSERT(retval == 0 || retval == 1);
82090 if (v1 < v2) {
82091 return retval ^ 1;
82092 } else {
82093 return retval;
82094 }
82095}
82096#endif
82097
82098#if defined(DUK_USE_PARANOID_MATH)
82099DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
82100 duk_small_int_t c1, s1, c2, s2;
82101
82102 DUK_ASSERT(retval == 0 || retval == 1);
82103 c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
82104 s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
82105 c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
82106 s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
82107
82108 if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
82109 return 0; /* Always false, regardless of negation. */
82110 }
82111
82112 if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
82113 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
82114 * steps e, f, and g.
82115 */
82116 return retval; /* false */
82117 }
82118
82119 if (d1 == d2) {
82120 return retval; /* false */
82121 }
82122
82123 if (c1 == DUK_FP_INFINITE && s1 == 0) {
82124 /* x == +Infinity */
82125 return retval; /* false */
82126 }
82127
82128 if (c2 == DUK_FP_INFINITE && s2 == 0) {
82129 /* y == +Infinity */
82130 return retval ^ 1; /* true */
82131 }
82132
82133 if (c2 == DUK_FP_INFINITE && s2 != 0) {
82134 /* y == -Infinity */
82135 return retval; /* false */
82136 }
82137
82138 if (c1 == DUK_FP_INFINITE && s1 != 0) {
82139 /* x == -Infinity */
82140 return retval ^ 1; /* true */
82141 }
82142
82143 if (d1 < d2) {
82144 return retval ^ 1; /* true */
82145 }
82146
82147 return retval; /* false */
82148}
82149#else /* DUK_USE_PARANOID_MATH */
82150DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
82151 /* This comparison tree relies doesn't match the exact steps in
82152 * E5 Section 11.8.5 but should produce the same results. The
82153 * steps rely on exact IEEE semantics for NaNs, etc.
82154 */
82155
82156 DUK_ASSERT(retval == 0 || retval == 1);
82157 if (d1 < d2) {
82158 /* In no case should both (d1 < d2) and (d2 < d1) be true.
82159 * It's possible that neither is true though, and that's
82160 * handled below.
82161 */
82162 DUK_ASSERT(!(d2 < d1));
82163
82164 /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN)
82165 * - d2 is +Infinity, d1 != +Infinity and NaN
82166 * - d1 is -Infinity, d2 != -Infinity and NaN
82167 */
82168 return retval ^ 1;
82169 } else {
82170 if (d2 < d1) {
82171 /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN)
82172 * - d1 is +Infinity, d2 != +Infinity and NaN
82173 * - d2 is -Infinity, d1 != -Infinity and NaN
82174 */
82175 return retval;
82176 } else {
82177 /* - d1 and/or d2 is NaN
82178 * - d1 and d2 are both +/- 0
82179 * - d1 == d2 (including infinities)
82180 */
82181 if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) {
82182 /* Note: undefined from Section 11.8.5 always
82183 * results in false return (see e.g. Section
82184 * 11.8.3) - hence special treatment here.
82185 */
82186 return 0; /* zero regardless of negation */
82187 } else {
82188 return retval;
82189 }
82190 }
82191 }
82192}
82193#endif /* DUK_USE_PARANOID_MATH */
82194
82195DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
82196 duk_double_t d1, d2;
82197 duk_small_int_t rc;
82198 duk_bool_t retval;
82199
82200 DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1); /* Rely on this flag being lowest. */
82201 retval = flags & DUK_COMPARE_FLAG_NEGATE;
82202 DUK_ASSERT(retval == 0 || retval == 1);
82203
82204 /* Fast path for fastints */
82205#if defined(DUK_USE_FASTINT)
82206 if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) {
82207 return duk__compare_fastint(retval,
82208 DUK_TVAL_GET_FASTINT(tv_x),
82209 DUK_TVAL_GET_FASTINT(tv_y));
82210 }
82211#endif /* DUK_USE_FASTINT */
82212
82213 /* Fast path for numbers (one of which may be a fastint) */
82214#if !defined(DUK_USE_PREFER_SIZE)
82215 if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) {
82216 return duk__compare_number(retval,
82217 DUK_TVAL_GET_NUMBER(tv_x),
82218 DUK_TVAL_GET_NUMBER(tv_y));
82219 }
82220#endif
82221
82222 /* Slow path */
82223
82224 duk_push_tval(thr, tv_x);
82225 duk_push_tval(thr, tv_y);
82226
82227 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
82228 duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
82229 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
82230 } else {
82231 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
82232 duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
82233 }
82234
82235 /* Note: reuse variables */
82236 tv_x = DUK_GET_TVAL_NEGIDX(thr, -2);
82237 tv_y = DUK_GET_TVAL_NEGIDX(thr, -1);
82238
82239 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
82240 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
82241 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
82242 DUK_ASSERT(h1 != NULL);
82243 DUK_ASSERT(h2 != NULL);
82244
82245 if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) {
82246 rc = duk_js_string_compare(h1, h2);
82247 duk_pop_2_unsafe(thr);
82248 if (rc < 0) {
82249 return retval ^ 1;
82250 } else {
82251 return retval;
82252 }
82253 }
82254
82255 /* One or both are Symbols: fall through to handle in the
82256 * generic path. Concretely, ToNumber() will fail.
82257 */
82258 }
82259
82260 /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */
82261#if 0
82262 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
82263 d1 = duk_to_number_m2(thr);
82264 d2 = duk_to_number_m1(thr);
82265 } else {
82266 d2 = duk_to_number_m1(thr);
82267 d1 = duk_to_number_m2(thr);
82268 }
82269#endif
82270 d1 = duk_to_number_m2(thr);
82271 d2 = duk_to_number_m1(thr);
82272
82273 /* We want to duk_pop_2_unsafe(thr); because the values are numbers
82274 * no decref check is needed.
82275 */
82276#if defined(DUK_USE_PREFER_SIZE)
82277 duk_pop_2_nodecref_unsafe(thr);
82278#else
82279 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2)));
82280 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1)));
82281 DUK_ASSERT(duk_get_top(thr) >= 2);
82282 thr->valstack_top -= 2;
82283 tv_x = thr->valstack_top;
82284 tv_y = tv_x + 1;
82285 DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */
82286 DUK_TVAL_SET_UNDEFINED(tv_y);
82287#endif
82288
82289 return duk__compare_number(retval, d1, d2);
82290}
82291
82292/*
82293 * instanceof
82294 */
82295
82296/*
82297 * ES2015 Section 7.3.19 describes the OrdinaryHasInstance() algorithm
82298 * which covers both bound and non-bound functions; in effect the algorithm
82299 * includes E5 Sections 11.8.6, 15.3.5.3, and 15.3.4.5.3.
82300 *
82301 * ES2015 Section 12.9.4 describes the instanceof operator which first
82302 * checks @@hasInstance well-known symbol and falls back to
82303 * OrdinaryHasInstance().
82304 *
82305 * Limited Proxy support: don't support 'getPrototypeOf' trap but
82306 * continue lookup in Proxy target if the value is a Proxy.
82307 */
82308
82309DUK_LOCAL duk_bool_t duk__js_instanceof_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_bool_t skip_sym_check) {
82310 duk_hobject *func;
82311 duk_hobject *val;
82312 duk_hobject *proto;
82313 duk_tval *tv;
82314 duk_bool_t skip_first;
82315 duk_uint_t sanity;
82316
82317 /*
82318 * Get the values onto the stack first. It would be possible to cover
82319 * some normal cases without resorting to the value stack.
82320 *
82321 * The right hand side could be a light function (as they generally
82322 * behave like objects). Light functions never have a 'prototype'
82323 * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
82324 * Using duk_require_hobject() is thus correct (except for error msg).
82325 */
82326
82327 duk_push_tval(thr, tv_x);
82328 duk_push_tval(thr, tv_y);
82329 func = duk_require_hobject(thr, -1);
82330 DUK_ASSERT(func != NULL);
82331
82332#if defined(DUK_USE_SYMBOL_BUILTIN)
82333 /*
82334 * @@hasInstance check, ES2015 Section 12.9.4, Steps 2-4.
82335 */
82336 if (!skip_sym_check) {
82337 if (duk_get_method_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)) {
82338 /* [ ... lhs rhs func ] */
82339 duk_insert(thr, -3); /* -> [ ... func lhs rhs ] */
82340 duk_swap_top(thr, -2); /* -> [ ... func rhs(this) lhs ] */
82341 duk_call_method(thr, 1);
82342 return duk_to_boolean_top_pop(thr);
82343 }
82344 }
82345#else
82346 DUK_UNREF(skip_sym_check);
82347#endif
82348
82349 /*
82350 * For bound objects, [[HasInstance]] just calls the target function
82351 * [[HasInstance]]. If that is again a bound object, repeat until
82352 * we find a non-bound Function object.
82353 *
82354 * The bound function chain is now "collapsed" so there can be only
82355 * one bound function in the chain.
82356 */
82357
82358 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
82359 /*
82360 * Note: of native ECMAScript objects, only Function instances
82361 * have a [[HasInstance]] internal property. Custom objects might
82362 * also have it, but not in current implementation.
82363 *
82364 * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
82365 */
82366 goto error_invalid_rval;
82367 }
82368
82369 if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
82370 duk_push_tval(thr, &((duk_hboundfunc *) (void *) func)->target);
82371 duk_replace(thr, -2);
82372 func = duk_require_hobject(thr, -1); /* lightfunc throws */
82373
82374 /* Rely on Function.prototype.bind() never creating bound
82375 * functions whose target is not proper.
82376 */
82377 DUK_ASSERT(func != NULL);
82378 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
82379 }
82380
82381 /*
82382 * 'func' is now a non-bound object which supports [[HasInstance]]
82383 * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
82384 * to execute E5 Section 15.3.5.3.
82385 */
82386
82387 DUK_ASSERT(func != NULL);
82388 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
82389 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
82390
82391 /* [ ... lval rval(func) ] */
82392
82393 /* For lightfuncs, buffers, and pointers start the comparison directly
82394 * from the virtual prototype object.
82395 */
82396 skip_first = 0;
82397 tv = DUK_GET_TVAL_NEGIDX(thr, -2);
82398 switch (DUK_TVAL_GET_TAG(tv)) {
82399 case DUK_TAG_LIGHTFUNC:
82400 val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
82401 DUK_ASSERT(val != NULL);
82402 break;
82403 case DUK_TAG_BUFFER:
82404 val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
82405 DUK_ASSERT(val != NULL);
82406 break;
82407 case DUK_TAG_POINTER:
82408 val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
82409 DUK_ASSERT(val != NULL);
82410 break;
82411 case DUK_TAG_OBJECT:
82412 skip_first = 1; /* Ignore object itself on first round. */
82413 val = DUK_TVAL_GET_OBJECT(tv);
82414 DUK_ASSERT(val != NULL);
82415 break;
82416 default:
82417 goto pop2_and_false;
82418 }
82419 DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */
82420
82421 /* Look up .prototype of rval. Leave it on the value stack in case it
82422 * has been virtualized (e.g. getter, Proxy trap).
82423 */
82424 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
82425#if defined(DUK_USE_VERBOSE_ERRORS)
82426 proto = duk_get_hobject(thr, -1);
82427 if (proto == NULL) {
82428 goto error_invalid_rval_noproto;
82429 }
82430#else
82431 proto = duk_require_hobject(thr, -1);
82432#endif
82433
82434 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
82435 do {
82436 /*
82437 * Note: prototype chain is followed BEFORE first comparison. This
82438 * means that the instanceof lval is never itself compared to the
82439 * rval.prototype property. This is apparently intentional, see E5
82440 * Section 15.3.5.3, step 4.a.
82441 *
82442 * Also note:
82443 *
82444 * js> (function() {}) instanceof Function
82445 * true
82446 * js> Function instanceof Function
82447 * true
82448 *
82449 * For the latter, h_proto will be Function.prototype, which is the
82450 * built-in Function prototype. Because Function.[[Prototype]] is
82451 * also the built-in Function prototype, the result is true.
82452 */
82453
82454 if (!val) {
82455 goto pop3_and_false;
82456 }
82457
82458 DUK_ASSERT(val != NULL);
82459#if defined(DUK_USE_ES6_PROXY)
82460 val = duk_hobject_resolve_proxy_target(val);
82461#endif
82462
82463 if (skip_first) {
82464 skip_first = 0;
82465 } else if (val == proto) {
82466 goto pop3_and_true;
82467 }
82468
82469 DUK_ASSERT(val != NULL);
82470 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
82471 } while (--sanity > 0);
82472
82473 DUK_ASSERT(sanity == 0);
82474 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
82475 DUK_WO_NORETURN(return 0;);
82476
82477 pop2_and_false:
82478 duk_pop_2_unsafe(thr);
82479 return 0;
82480
82481 pop3_and_false:
82482 duk_pop_3_unsafe(thr);
82483 return 0;
82484
82485 pop3_and_true:
82486 duk_pop_3_unsafe(thr);
82487 return 1;
82488
82489 error_invalid_rval:
82490 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL);
82491 DUK_WO_NORETURN(return 0;);
82492
82493#if defined(DUK_USE_VERBOSE_ERRORS)
82494 error_invalid_rval_noproto:
82495 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO);
82496 DUK_WO_NORETURN(return 0;);
82497#endif
82498}
82499
82500#if defined(DUK_USE_SYMBOL_BUILTIN)
82501DUK_INTERNAL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
82502 return duk__js_instanceof_helper(thr, tv_x, tv_y, 1 /*skip_sym_check*/);
82503}
82504#endif
82505
82506DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
82507 return duk__js_instanceof_helper(thr, tv_x, tv_y, 0 /*skip_sym_check*/);
82508}
82509
82510/*
82511 * in
82512 */
82513
82514/*
82515 * E5 Sections 11.8.7, 8.12.6.
82516 *
82517 * Basically just a property existence check using [[HasProperty]].
82518 */
82519
82520DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
82521 duk_bool_t retval;
82522
82523 /*
82524 * Get the values onto the stack first. It would be possible to cover
82525 * some normal cases without resorting to the value stack (e.g. if
82526 * lval is already a string).
82527 */
82528
82529 /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
82530 * must be string coerced before the internal HasProperty() algorithm is
82531 * invoked. A fast path skipping coercion could be safely implemented for
82532 * numbers (as number-to-string coercion has no side effects). For ES2015
82533 * proxy behavior, the trap 'key' argument must be in a string coerced
82534 * form (which is a shame).
82535 */
82536
82537 /* TypeError if rval is not an object or object like (e.g. lightfunc
82538 * or plain buffer).
82539 */
82540 duk_push_tval(thr, tv_x);
82541 duk_push_tval(thr, tv_y);
82542 duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
82543
82544 (void) duk_to_property_key_hstring(thr, -2);
82545
82546 retval = duk_hobject_hasprop(thr,
82547 DUK_GET_TVAL_NEGIDX(thr, -1),
82548 DUK_GET_TVAL_NEGIDX(thr, -2));
82549
82550 duk_pop_2_unsafe(thr);
82551 return retval;
82552}
82553
82554/*
82555 * typeof
82556 *
82557 * E5 Section 11.4.3.
82558 *
82559 * Very straightforward. The only question is what to return for our
82560 * non-standard tag / object types.
82561 *
82562 * There is an unfortunate string constant define naming problem with
82563 * typeof return values for e.g. "Object" and "object"; careful with
82564 * the built-in string defines. The LC_XXX defines are used for the
82565 * lowercase variants now.
82566 */
82567
82568DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) {
82569 duk_small_uint_t stridx = 0;
82570
82571 switch (DUK_TVAL_GET_TAG(tv_x)) {
82572 case DUK_TAG_UNDEFINED: {
82573 stridx = DUK_STRIDX_LC_UNDEFINED;
82574 break;
82575 }
82576 case DUK_TAG_NULL: {
82577 /* Note: not a typo, "object" is returned for a null value. */
82578 stridx = DUK_STRIDX_LC_OBJECT;
82579 break;
82580 }
82581 case DUK_TAG_BOOLEAN: {
82582 stridx = DUK_STRIDX_LC_BOOLEAN;
82583 break;
82584 }
82585 case DUK_TAG_POINTER: {
82586 /* Implementation specific. */
82587 stridx = DUK_STRIDX_LC_POINTER;
82588 break;
82589 }
82590 case DUK_TAG_STRING: {
82591 duk_hstring *str;
82592
82593 /* All internal keys are identified as Symbols. */
82594 str = DUK_TVAL_GET_STRING(tv_x);
82595 DUK_ASSERT(str != NULL);
82596 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) {
82597 stridx = DUK_STRIDX_LC_SYMBOL;
82598 } else {
82599 stridx = DUK_STRIDX_LC_STRING;
82600 }
82601 break;
82602 }
82603 case DUK_TAG_OBJECT: {
82604 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
82605 DUK_ASSERT(obj != NULL);
82606 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
82607 stridx = DUK_STRIDX_LC_FUNCTION;
82608 } else {
82609 stridx = DUK_STRIDX_LC_OBJECT;
82610 }
82611 break;
82612 }
82613 case DUK_TAG_BUFFER: {
82614 /* Implementation specific. In Duktape 1.x this would be
82615 * 'buffer', in Duktape 2.x changed to 'object' because plain
82616 * buffers now mimic Uint8Array objects.
82617 */
82618 stridx = DUK_STRIDX_LC_OBJECT;
82619 break;
82620 }
82621 case DUK_TAG_LIGHTFUNC: {
82622 stridx = DUK_STRIDX_LC_FUNCTION;
82623 break;
82624 }
82625#if defined(DUK_USE_FASTINT)
82626 case DUK_TAG_FASTINT:
82627#endif
82628 default: {
82629 /* number */
82630 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
82631 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
82632 stridx = DUK_STRIDX_LC_NUMBER;
82633 break;
82634 }
82635 }
82636
82637 DUK_ASSERT_STRIDX_VALID(stridx);
82638 return stridx;
82639}
82640
82641/*
82642 * IsArray()
82643 */
82644
82645DUK_INTERNAL duk_bool_t duk_js_isarray_hobject(duk_hobject *h) {
82646 DUK_ASSERT(h != NULL);
82647#if defined(DUK_USE_ES6_PROXY)
82648 h = duk_hobject_resolve_proxy_target(h);
82649#endif
82650 return (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
82651}
82652
82653DUK_INTERNAL duk_bool_t duk_js_isarray(duk_tval *tv) {
82654 DUK_ASSERT(tv != NULL);
82655 if (DUK_TVAL_IS_OBJECT(tv)) {
82656 return duk_js_isarray_hobject(DUK_TVAL_GET_OBJECT(tv));
82657 }
82658 return 0;
82659}
82660
82661/*
82662 * Array index and length
82663 *
82664 * Array index: E5 Section 15.4
82665 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
82666 */
82667
82668/* Compure array index from string context, or return a "not array index"
82669 * indicator.
82670 */
82671DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) {
82672 duk_uarridx_t res;
82673
82674 /* Only strings with byte length 1-10 can be 32-bit array indices.
82675 * Leading zeroes (except '0' alone), plus/minus signs are not allowed.
82676 * We could do a lot of prechecks here, but since most strings won't
82677 * start with any digits, it's simpler to just parse the number and
82678 * fail quickly.
82679 */
82680
82681 res = 0;
82682 if (blen == 0) {
82683 goto parse_fail;
82684 }
82685 do {
82686 duk_uarridx_t dig;
82687 dig = (duk_uarridx_t) (*str++) - DUK_ASC_0;
82688
82689 if (dig <= 9U) {
82690 /* Careful overflow handling. When multiplying by 10:
82691 * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding
82692 * 0...9 is safe.
82693 * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding
82694 * 0...5 is safe, 6...9 overflows.
82695 * - 0x1999999a x 10 = 0x100000004: always overflow.
82696 */
82697 if (DUK_UNLIKELY(res >= 0x19999999UL)) {
82698 if (res >= 0x1999999aUL) {
82699 /* Always overflow. */
82700 goto parse_fail;
82701 }
82702 DUK_ASSERT(res == 0x19999999UL);
82703 if (dig >= 6U) {
82704 goto parse_fail;
82705 }
82706 res = 0xfffffffaUL + dig;
82707 DUK_ASSERT(res >= 0xfffffffaUL);
82708 DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */
82709 } else {
82710 res = res * 10U + dig;
82711 if (DUK_UNLIKELY(res == 0)) {
82712 /* If 'res' is 0, previous 'res' must
82713 * have been 0 and we scanned in a zero.
82714 * This is only allowed if blen == 1,
82715 * i.e. the exact string '0'.
82716 */
82717 if (blen == (duk_uint32_t) 1) {
82718 return 0;
82719 }
82720 goto parse_fail;
82721 }
82722 }
82723 } else {
82724 /* Because 'dig' is unsigned, catches both values
82725 * above '9' and below '0'.
82726 */
82727 goto parse_fail;
82728 }
82729 } while (--blen > 0);
82730
82731 return res;
82732
82733 parse_fail:
82734 return DUK_HSTRING_NO_ARRAY_INDEX;
82735}
82736
82737#if !defined(DUK_USE_HSTRING_ARRIDX)
82738/* Get array index for a string which is known to be an array index. This helper
82739 * is needed when duk_hstring doesn't concretely store the array index, but strings
82740 * are flagged as array indices at intern time.
82741 */
82742DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) {
82743 const duk_uint8_t *p;
82744 duk_uarridx_t res;
82745 duk_uint8_t t;
82746
82747 DUK_ASSERT(h != NULL);
82748 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h));
82749
82750 p = DUK_HSTRING_GET_DATA(h);
82751 res = 0;
82752 for (;;) {
82753 t = *p++;
82754 if (DUK_UNLIKELY(t == 0)) {
82755 /* Scanning to NUL is always safe for interned strings. */
82756 break;
82757 }
82758 DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9);
82759 res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0;
82760 }
82761 return res;
82762}
82763
82764DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) {
82765 DUK_ASSERT(h != NULL);
82766 if (!DUK_HSTRING_HAS_ARRIDX(h)) {
82767 return DUK_HSTRING_NO_ARRAY_INDEX;
82768 }
82769 return duk_js_to_arrayindex_hstring_fast_known(h);
82770}
82771#endif /* DUK_USE_HSTRING_ARRIDX */
82772#line 1 "duk_js_var.c"
82773/*
82774 * Identifier access and function closure handling.
82775 *
82776 * Provides the primitives for slow path identifier accesses: GETVAR,
82777 * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should
82778 * be used for most identifier accesses. Consequently, these slow path
82779 * primitives should be optimized for maximum compactness.
82780 *
82781 * ECMAScript environment records (declarative and object) are represented
82782 * as internal objects with control keys. Environment records have a
82783 * parent record ("outer environment reference") which is represented by
82784 * the implicit prototype for technical reasons (in other words, it is a
82785 * convenient field). The prototype chain is not followed in the ordinary
82786 * sense for variable lookups.
82787 *
82788 * See identifier-handling.rst for more details on the identifier algorithms
82789 * and the internal representation. See function-objects.rst for details on
82790 * what function templates and instances are expected to look like.
82791 *
82792 * Care must be taken to avoid duk_tval pointer invalidation caused by
82793 * e.g. value stack or object resizing.
82794 *
82795 * TODO: properties for function instances could be initialized much more
82796 * efficiently by creating a property allocation for a certain size and
82797 * filling in keys and values directly (and INCREFing both with "bulk incref"
82798 * primitives.
82799 *
82800 * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
82801 * awkward (especially because they follow the prototype chain); rework
82802 * if "raw" own property helpers are added.
82803 */
82804
82805/* #include duk_internal.h -> already included */
82806
82807/*
82808 * Local result type for duk__get_identifier_reference() lookup.
82809 */
82810
82811typedef struct {
82812 duk_hobject *env;
82813 duk_hobject *holder; /* for object-bound identifiers */
82814 duk_tval *value; /* for register-bound and declarative env identifiers */
82815 duk_uint_t attrs; /* property attributes for identifier (relevant if value != NULL) */
82816 duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */
82817} duk__id_lookup_result;
82818
82819/*
82820 * Create a new function object based on a "template function" which contains
82821 * compiled bytecode, constants, etc, but lacks a lexical environment.
82822 *
82823 * ECMAScript requires that each created closure is a separate object, with
82824 * its own set of editable properties. However, structured property values
82825 * (such as the formal arguments list and the variable map) are shared.
82826 * Also the bytecode, constants, and inner functions are shared.
82827 *
82828 * See E5 Section 13.2 for detailed requirements on the function objects;
82829 * there are no similar requirements for function "templates" which are an
82830 * implementation dependent internal feature. Also see function-objects.rst
82831 * for a discussion on the function instance properties provided by this
82832 * implementation.
82833 *
82834 * Notes:
82835 *
82836 * * Order of internal properties should match frequency of use, since the
82837 * properties will be linearly scanned on lookup (functions usually don't
82838 * have enough properties to warrant a hash part).
82839 *
82840 * * The created closure is independent of its template; they do share the
82841 * same 'data' buffer object, but the template object itself can be freed
82842 * even if the closure object remains reachable.
82843 */
82844
82845DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) {
82846 duk_tval *tv, *tv_end;
82847 duk_hobject **funcs, **funcs_end;
82848
82849 DUK_UNREF(thr);
82850
82851 /* If function creation fails due to out-of-memory, the data buffer
82852 * pointer may be NULL in some cases. That's actually possible for
82853 * GC code, but shouldn't be possible here because the incomplete
82854 * function will be unwound from the value stack and never instantiated.
82855 */
82856 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL);
82857
82858 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f);
82859 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f);
82860 while (tv < tv_end) {
82861 DUK_TVAL_INCREF(thr, tv);
82862 tv++;
82863 }
82864
82865 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f);
82866 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f);
82867 while (funcs < funcs_end) {
82868 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
82869 funcs++;
82870 }
82871}
82872
82873/* Push a new closure on the stack.
82874 *
82875 * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
82876 * is created when the function is called, only outer_lex_env matters
82877 * (outer_var_env is ignored and may or may not be same as outer_lex_env).
82878 */
82879
82880DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
82881 /* order: most frequent to least frequent */
82882 DUK_STRIDX_INT_VARMAP,
82883 DUK_STRIDX_INT_FORMALS,
82884#if defined(DUK_USE_PC2LINE)
82885 DUK_STRIDX_INT_PC2LINE,
82886#endif
82887#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
82888 DUK_STRIDX_FILE_NAME,
82889#endif
82890#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
82891 DUK_STRIDX_INT_SOURCE
82892#endif
82893};
82894
82895DUK_INTERNAL
82896void duk_js_push_closure(duk_hthread *thr,
82897 duk_hcompfunc *fun_temp,
82898 duk_hobject *outer_var_env,
82899 duk_hobject *outer_lex_env,
82900 duk_bool_t add_auto_proto) {
82901 duk_hcompfunc *fun_clos;
82902 duk_harray *formals;
82903 duk_small_uint_t i;
82904 duk_uint_t len_value;
82905
82906 DUK_ASSERT(fun_temp != NULL);
82907 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL);
82908 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL);
82909 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL);
82910 DUK_ASSERT(outer_var_env != NULL);
82911 DUK_ASSERT(outer_lex_env != NULL);
82912 DUK_UNREF(len_value);
82913
82914 DUK_STATS_INC(thr->heap, stats_envrec_pushclosure);
82915
82916 fun_clos = duk_push_hcompfunc(thr);
82917 DUK_ASSERT(fun_clos != NULL);
82918 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
82919
82920 duk_push_hobject(thr, &fun_temp->obj); /* -> [ ... closure template ] */
82921
82922 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos));
82923 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL);
82924 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL);
82925 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL);
82926
82927 DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp));
82928 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp));
82929 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp));
82930
82931 /* Note: all references inside 'data' need to get their refcounts
82932 * upped too. This is the case because refcounts are decreased
82933 * through every function referencing 'data' independently.
82934 */
82935
82936 DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos));
82937 duk__inc_data_inner_refcounts(thr, fun_temp);
82938
82939 fun_clos->nregs = fun_temp->nregs;
82940 fun_clos->nargs = fun_temp->nargs;
82941#if defined(DUK_USE_DEBUGGER_SUPPORT)
82942 fun_clos->start_line = fun_temp->start_line;
82943 fun_clos->end_line = fun_temp->end_line;
82944#endif
82945
82946 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL);
82947 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL);
82948 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL);
82949
82950 /* XXX: Could also copy from template, but there's no way to have any
82951 * other value here now (used code has no access to the template).
82952 * Prototype is set by duk_push_hcompfunc().
82953 */
82954 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
82955#if 0
82956 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
82957#endif
82958
82959 /* Copy duk_hobject flags as is from the template using a mask.
82960 * Leave out duk_heaphdr owned flags just in case (e.g. if there's
82961 * some GC flag or similar). Some flags can then be adjusted
82962 * separately if necessary.
82963 */
82964
82965 /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */
82966 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp));
82967 DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx",
82968 (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp),
82969 (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos)));
82970
82971 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
82972 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj));
82973 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj));
82974 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj));
82975 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj));
82976 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
82977 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
82978 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
82979 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
82980 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
82981
82982 if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) {
82983 /* If the template is not constructable don't add an automatic
82984 * .prototype property. This is the case for e.g. ES2015 object
82985 * literal getters/setters and method definitions.
82986 */
82987 add_auto_proto = 0;
82988 }
82989
82990 /*
82991 * Setup environment record properties based on the template and
82992 * its flags.
82993 *
82994 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
82995 * records represent identifiers "outside" the function; the
82996 * "inner" environment records are created on demand. Otherwise,
82997 * the environment records are those that will be directly used
82998 * (e.g. for declarations).
82999 *
83000 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
83001 * so _Varenv is only set if _Lexenv != _Varenv.
83002 *
83003 * This is relatively complex, see doc/identifier-handling.rst.
83004 */
83005
83006 if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) {
83007#if defined(DUK_USE_FUNC_NAME_PROPERTY)
83008 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) {
83009 duk_hobject *proto;
83010 duk_hdecenv *new_env;
83011
83012 /*
83013 * Named function expression, name needs to be bound
83014 * in an intermediate environment record. The "outer"
83015 * lexical/variable environment will thus be:
83016 *
83017 * a) { funcname: <func>, __prototype: outer_lex_env }
83018 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
83019 */
83020
83021 if (outer_lex_env) {
83022 proto = outer_lex_env;
83023 } else {
83024 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
83025 }
83026
83027 /* -> [ ... closure template env ] */
83028 new_env = duk_hdecenv_alloc(thr,
83029 DUK_HOBJECT_FLAG_EXTENSIBLE |
83030 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
83031 DUK_ASSERT(new_env != NULL);
83032 duk_push_hobject(thr, (duk_hobject *) new_env);
83033
83034 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
83035 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto);
83036 DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto);
83037
83038 DUK_ASSERT(new_env->thread == NULL); /* Closed. */
83039 DUK_ASSERT(new_env->varmap == NULL);
83040
83041 /* It's important that duk_xdef_prop() is a 'raw define' so that any
83042 * properties in an ancestor are never an issue (they should never be
83043 * e.g. non-writable, but just in case).
83044 *
83045 * Because template objects are not visible to user code, the case
83046 * where .name is missing shouldn't happen in practice. It it does,
83047 * the name 'undefined' gets bound and maps to the closure (which is
83048 * a bit odd, but safe).
83049 */
83050 (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
83051 /* -> [ ... closure template env funcname ] */
83052 duk_dup_m4(thr); /* -> [ ... closure template env funcname closure ] */
83053 duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
83054 /* env[funcname] = closure */
83055
83056 /* [ ... closure template env ] */
83057
83058 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env);
83059 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env);
83060 DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
83061 DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
83062 duk_pop_unsafe(thr);
83063
83064 /* [ ... closure template ] */
83065 }
83066 else
83067#endif /* DUK_USE_FUNC_NAME_PROPERTY */
83068 {
83069 /*
83070 * Other cases (function declaration, anonymous function expression,
83071 * strict direct eval code). The "outer" environment will be whatever
83072 * the caller gave us.
83073 */
83074
83075 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
83076 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env);
83077 DUK_HOBJECT_INCREF(thr, outer_lex_env);
83078 DUK_HOBJECT_INCREF(thr, outer_lex_env);
83079
83080 /* [ ... closure template ] */
83081 }
83082 } else {
83083 /*
83084 * Function gets no new environment when called. This is the
83085 * case for global code, indirect eval code, and non-strict
83086 * direct eval code. There is no direct correspondence to the
83087 * E5 specification, as global/eval code is not exposed as a
83088 * function.
83089 */
83090
83091 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
83092
83093 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
83094 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env);
83095 DUK_HOBJECT_INCREF(thr, outer_lex_env); /* NULLs not allowed; asserted on entry */
83096 DUK_HOBJECT_INCREF(thr, outer_var_env);
83097 }
83098 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO",
83099 (duk_heaphdr *) fun_clos->var_env,
83100 (duk_heaphdr *) fun_clos->lex_env));
83101
83102 /* Call handling assumes this for all callable closures. */
83103 DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL);
83104 DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL);
83105
83106 /*
83107 * Copy some internal properties directly
83108 *
83109 * The properties will be non-writable and non-enumerable, but
83110 * configurable.
83111 *
83112 * Function templates are bare objects, so inheritance of internal
83113 * Symbols is not an issue here even when using ordinary property
83114 * reads. The function instance created is not bare, so internal
83115 * Symbols must be defined without inheritance checks.
83116 */
83117
83118 /* [ ... closure template ] */
83119
83120 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
83121 (duk_tval *) duk_get_tval(thr, -2),
83122 (duk_tval *) duk_get_tval(thr, -1)));
83123
83124 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
83125 duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
83126 if (duk_xget_owndataprop_stridx_short(thr, -1, stridx)) {
83127 /* [ ... closure template val ] */
83128 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
83129 duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C);
83130 } else {
83131 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
83132 duk_pop_unsafe(thr);
83133 }
83134 }
83135
83136 /*
83137 * "length" maps to number of formals (E5 Section 13.2) for function
83138 * declarations/expressions (non-bound functions). Note that 'nargs'
83139 * is NOT necessarily equal to the number of arguments. Use length
83140 * of _Formals; if missing, assume nargs matches .length.
83141 */
83142
83143 /* [ ... closure template ] */
83144
83145 formals = duk_hobject_get_formals(thr, (duk_hobject *) fun_temp);
83146 if (formals) {
83147 len_value = (duk_uint_t) formals->length;
83148 DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value));
83149 } else {
83150 len_value = fun_temp->nargs;
83151 DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value));
83152 }
83153
83154 duk_push_uint(thr, len_value); /* [ ... closure template len_value ] */
83155 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
83156
83157 /*
83158 * "prototype" is, by default, a fresh object with the "constructor"
83159 * property.
83160 *
83161 * Note that this creates a circular reference for every function
83162 * instance (closure) which prevents refcount-based collection of
83163 * function instances.
83164 *
83165 * XXX: Try to avoid creating the default prototype object, because
83166 * many functions are not used as constructors and the default
83167 * prototype is unnecessary. Perhaps it could be created on-demand
83168 * when it is first accessed?
83169 */
83170
83171 /* [ ... closure template ] */
83172
83173 if (add_auto_proto) {
83174 duk_push_object(thr); /* -> [ ... closure template newobj ] */
83175 duk_dup_m3(thr); /* -> [ ... closure template newobj closure ] */
83176 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
83177 duk_compact(thr, -1); /* compact the prototype */
83178 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
83179 }
83180
83181 /*
83182 * "arguments" and "caller" must be mapped to throwers for strict
83183 * mode and bound functions (E5 Section 15.3.5).
83184 *
83185 * XXX: This is expensive to have for every strict function instance.
83186 * Try to implement as virtual properties or on-demand created properties.
83187 */
83188
83189 /* [ ... closure template ] */
83190
83191 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
83192 duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER);
83193 duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS);
83194 } else {
83195#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
83196 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
83197 duk_push_null(thr);
83198 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
83199#else
83200 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
83201#endif
83202 }
83203
83204 /*
83205 * "name" used to be non-standard but is now defined by ES2015.
83206 * In ES2015/ES2016 the .name property is configurable.
83207 */
83208
83209 /* [ ... closure template ] */
83210
83211#if defined(DUK_USE_FUNC_NAME_PROPERTY)
83212 /* XXX: Look for own property only; doesn't matter much because
83213 * templates are bare objects.
83214 */
83215 if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) {
83216 /* [ ... closure template name ] */
83217 DUK_ASSERT(duk_is_string(thr, -1));
83218 DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(thr, -1)));
83219 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */
83220 } else {
83221 /* Anonymous functions don't have a .name in ES2015, so don't set
83222 * it on the instance either. The instance will then inherit
83223 * it from Function.prototype.name.
83224 */
83225 DUK_DD(DUK_DDPRINT("not setting function instance .name"));
83226 duk_pop_unsafe(thr);
83227 }
83228#endif
83229
83230 /*
83231 * Compact the closure, in most cases no properties will be added later.
83232 * Also, without this the closures end up having unused property slots
83233 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
83234 * A better future solution would be to allocate the closure directly
83235 * to correct size (and setup the properties directly without going
83236 * through the API).
83237 */
83238
83239 duk_compact(thr, -2);
83240
83241 /*
83242 * Some assertions (E5 Section 13.2).
83243 */
83244
83245 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
83246 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
83247 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
83248 DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0);
83249 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0);
83250 /* May be missing .name */
83251 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
83252 duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0);
83253 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
83254 duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
83255
83256 /*
83257 * Finish
83258 */
83259
83260 /* [ ... closure template ] */
83261
83262 DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
83263 (duk_tval *) duk_get_tval(thr, -1),
83264 (duk_tval *) duk_get_tval(thr, -2)));
83265
83266 duk_pop_unsafe(thr);
83267
83268 /* [ ... closure ] */
83269}
83270
83271/*
83272 * Delayed activation environment record initialization (for functions
83273 * with NEWENV).
83274 *
83275 * The non-delayed initialization is handled by duk_handle_call().
83276 */
83277
83278DUK_LOCAL void duk__preallocate_env_entries(duk_hthread *thr, duk_hobject *varmap, duk_hobject *env) {
83279 duk_uint_fast32_t i;
83280
83281 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
83282 duk_hstring *key;
83283
83284 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
83285 DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */
83286 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
83287
83288 /* Predefine as 'undefined' to reserve a property slot.
83289 * This makes the unwind process (where register values
83290 * are copied to the env object) safe against throwing.
83291 *
83292 * XXX: This could be made much faster by creating the
83293 * property table directly.
83294 */
83295 duk_push_undefined(thr);
83296 DUK_DDD(DUK_DDDPRINT("preallocate env entry for key %!O", key));
83297 duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE);
83298 }
83299}
83300
83301/* shared helper */
83302DUK_INTERNAL
83303duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
83304 duk_hobject *func,
83305 duk_size_t bottom_byteoff) {
83306 duk_hdecenv *env;
83307 duk_hobject *parent;
83308 duk_hcompfunc *f;
83309
83310 DUK_ASSERT(thr != NULL);
83311 DUK_ASSERT(func != NULL);
83312
83313 DUK_STATS_INC(thr->heap, stats_envrec_create);
83314
83315 f = (duk_hcompfunc *) func;
83316 parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
83317 if (!parent) {
83318 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
83319 }
83320
83321 env = duk_hdecenv_alloc(thr,
83322 DUK_HOBJECT_FLAG_EXTENSIBLE |
83323 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
83324 DUK_ASSERT(env != NULL);
83325 duk_push_hobject(thr, (duk_hobject *) env);
83326
83327 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
83328 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent);
83329 DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */
83330
83331 /* open scope information, for compiled functions only */
83332
83333 DUK_ASSERT(env->thread == NULL);
83334 DUK_ASSERT(env->varmap == NULL);
83335 DUK_ASSERT(env->regbase_byteoff == 0);
83336 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
83337 duk_hobject *varmap;
83338
83339 varmap = duk_hobject_get_varmap(thr, func);
83340 if (varmap != NULL) {
83341 env->varmap = varmap;
83342 DUK_HOBJECT_INCREF(thr, varmap);
83343 env->thread = thr;
83344 DUK_HTHREAD_INCREF(thr, thr);
83345 env->regbase_byteoff = bottom_byteoff;
83346
83347 /* Preallocate env property table to avoid potential
83348 * for out-of-memory on unwind when the env is closed.
83349 */
83350 duk__preallocate_env_entries(thr, varmap, (duk_hobject *) env);
83351 } else {
83352 /* If function has no _Varmap, leave the environment closed. */
83353 DUK_ASSERT(env->thread == NULL);
83354 DUK_ASSERT(env->varmap == NULL);
83355 DUK_ASSERT(env->regbase_byteoff == 0);
83356 }
83357 }
83358
83359 return (duk_hobject *) env;
83360}
83361
83362DUK_INTERNAL
83363void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
83364 duk_activation *act) {
83365 duk_hobject *func;
83366 duk_hobject *env;
83367
83368 DUK_ASSERT(thr != NULL);
83369 func = DUK_ACT_GET_FUNC(act);
83370 DUK_ASSERT(func != NULL);
83371 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */
83372
83373 /*
83374 * Delayed initialization only occurs for 'NEWENV' functions.
83375 */
83376
83377 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
83378 DUK_ASSERT(act->lex_env == NULL);
83379 DUK_ASSERT(act->var_env == NULL);
83380
83381 DUK_STATS_INC(thr->heap, stats_envrec_delayedcreate);
83382
83383 env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
83384 DUK_ASSERT(env != NULL);
83385 /* 'act' is a stable pointer, so still OK. */
83386
83387 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
83388#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
83389 {
83390 duk_hobject *p = env;
83391 while (p) {
83392 DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
83393 p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
83394 }
83395 }
83396#endif
83397
83398 act->lex_env = env;
83399 act->var_env = env;
83400 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
83401 DUK_HOBJECT_INCREF(thr, env);
83402
83403 duk_pop_unsafe(thr);
83404}
83405
83406/*
83407 * Closing environment records.
83408 *
83409 * The environment record MUST be closed with the thread where its activation
83410 * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase
83411 * and varmap must still be valid. On entry, 'env' must be reachable.
83412 */
83413
83414DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) {
83415 duk_uint_fast32_t i;
83416 duk_hobject *varmap;
83417 duk_hstring *key;
83418 duk_tval *tv;
83419 duk_uint_t regnum;
83420
83421 DUK_ASSERT(thr != NULL);
83422 DUK_ASSERT(env != NULL);
83423
83424 if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) {
83425 DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env));
83426 return;
83427 }
83428
83429 varmap = ((duk_hdecenv *) env)->varmap;
83430 if (varmap == NULL) {
83431 DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env));
83432
83433 return;
83434 }
83435 DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL);
83436 DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env);
83437
83438 DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env));
83439 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
83440
83441 /* Env must be closed in the same thread as where it runs. */
83442 DUK_ASSERT(((duk_hdecenv *) env)->thread == thr);
83443
83444 /* XXX: additional conditions when to close variables? we don't want to do it
83445 * unless the environment may have "escaped" (referenced in a function closure).
83446 * With delayed environments, the existence is probably good enough of a check.
83447 */
83448
83449 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
83450 * - being compacted and unmodified during this process
83451 * - not containing an array part
83452 * - having correct value types
83453 */
83454
83455 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
83456
83457 /* Copy over current variable values from value stack to the
83458 * environment record. The scope object is empty but may
83459 * inherit from another scope which has conflicting names.
83460 */
83461
83462 /* XXX: Do this using a once allocated entry area, no side effects.
83463 * Hash part would need special treatment however (maybe copy, and
83464 * then realloc with hash part if large enough).
83465 */
83466 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
83467 duk_size_t regbase_byteoff;
83468
83469 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
83470 DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */
83471 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
83472
83473 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
83474 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
83475 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */
83476#if defined(DUK_USE_FASTINT)
83477 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
83478 regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv);
83479#else
83480 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
83481#endif
83482
83483 regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff;
83484 DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack);
83485 DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top);
83486
83487 /* Write register value into env as named properties.
83488 * If property already exists, overwrites silently.
83489 * Property is writable, but not deletable (not configurable
83490 * in terms of property attributes).
83491 *
83492 * This property write must not throw because we're unwinding
83493 * and unwind code is not allowed to throw at present. The
83494 * call itself has no such guarantees, but we've preallocated
83495 * entries for each property when the env was created, so no
83496 * out-of-memory error should be possible. If this guarantee
83497 * is not provided, problems like GH-476 may happen.
83498 */
83499 duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum));
83500 DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T",
83501 (duk_heaphdr *) key,
83502 (long) regnum,
83503 (duk_tval *) duk_get_tval(thr, -1)));
83504 duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE);
83505 }
83506
83507 /* NULL atomically to avoid inconsistent state + side effects. */
83508 DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread);
83509 DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap);
83510 ((duk_hdecenv *) env)->thread = NULL;
83511 ((duk_hdecenv *) env)->varmap = NULL;
83512
83513 DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env));
83514}
83515
83516/*
83517 * GETIDREF: a GetIdentifierReference-like helper.
83518 *
83519 * Provides a parent traversing lookup and a single level lookup
83520 * (for HasBinding).
83521 *
83522 * Instead of returning the value, returns a bunch of values allowing
83523 * the caller to read, write, or delete the binding. Value pointers
83524 * are duk_tval pointers which can be mutated directly as long as
83525 * refcounts are properly updated. Note that any operation which may
83526 * reallocate valstacks or compact objects may invalidate the returned
83527 * duk_tval (but not object) pointers, so caller must be very careful.
83528 *
83529 * If starting environment record 'env' is given, 'act' is ignored.
83530 * However, if 'env' is NULL, the caller may identify, in 'act', an
83531 * activation which hasn't had its declarative environment initialized
83532 * yet. The activation registers are then looked up, and its parent
83533 * traversed normally.
83534 *
83535 * The 'out' structure values are only valid if the function returns
83536 * success (non-zero).
83537 */
83538
83539/* lookup name from an open declarative record's registers */
83540DUK_LOCAL
83541duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
83542 duk_hstring *name,
83543 duk_hdecenv *env,
83544 duk__id_lookup_result *out) {
83545 duk_tval *tv;
83546 duk_size_t reg_rel;
83547
83548 DUK_ASSERT(thr != NULL);
83549 DUK_ASSERT(name != NULL);
83550 DUK_ASSERT(env != NULL);
83551 DUK_ASSERT(out != NULL);
83552
83553 DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env));
83554 DUK_HDECENV_ASSERT_VALID(env);
83555
83556 if (env->thread == NULL) {
83557 /* already closed */
83558 return 0;
83559 }
83560 DUK_ASSERT(env->varmap != NULL);
83561
83562 tv = duk_hobject_find_entry_tval_ptr(thr->heap, env->varmap, name);
83563 if (DUK_UNLIKELY(tv == NULL)) {
83564 return 0;
83565 }
83566
83567 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
83568 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */
83569#if defined(DUK_USE_FASTINT)
83570 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
83571 reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv);
83572#else
83573 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
83574#endif
83575 DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
83576
83577 tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel);
83578 DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */
83579
83580 out->value = tv;
83581 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
83582 out->env = (duk_hobject *) env;
83583 out->holder = NULL;
83584 out->has_this = 0;
83585 return 1;
83586}
83587
83588/* lookup name from current activation record's functions' registers */
83589DUK_LOCAL
83590duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
83591 duk_hstring *name,
83592 duk_activation *act,
83593 duk__id_lookup_result *out) {
83594 duk_tval *tv;
83595 duk_hobject *func;
83596 duk_hobject *varmap;
83597 duk_size_t reg_rel;
83598
83599 DUK_ASSERT(thr != NULL);
83600 DUK_ASSERT(name != NULL);
83601 DUK_ASSERT(act != NULL);
83602 DUK_ASSERT(out != NULL);
83603
83604 func = DUK_ACT_GET_FUNC(act);
83605 DUK_ASSERT(func != NULL);
83606 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
83607
83608 if (!DUK_HOBJECT_IS_COMPFUNC(func)) {
83609 return 0;
83610 }
83611
83612 /* XXX: move varmap to duk_hcompfunc struct field? */
83613 varmap = duk_hobject_get_varmap(thr, func);
83614 if (!varmap) {
83615 return 0;
83616 }
83617
83618 tv = duk_hobject_find_entry_tval_ptr(thr->heap, varmap, name);
83619 if (!tv) {
83620 return 0;
83621 }
83622 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
83623 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
83624 DUK_ASSERT_DISABLE(reg_rel >= 0);
83625 DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs);
83626
83627 tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
83628 tv += reg_rel;
83629
83630 out->value = tv;
83631 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
83632 out->env = NULL;
83633 out->holder = NULL;
83634 out->has_this = 0;
83635 return 1;
83636}
83637
83638DUK_LOCAL
83639duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
83640 duk_hobject *env,
83641 duk_hstring *name,
83642 duk_activation *act,
83643 duk_bool_t parents,
83644 duk__id_lookup_result *out) {
83645 duk_tval *tv;
83646 duk_uint_t sanity;
83647
83648 DUK_ASSERT(thr != NULL);
83649 DUK_ASSERT(env != NULL || act != NULL);
83650 DUK_ASSERT(name != NULL);
83651 DUK_ASSERT(out != NULL);
83652
83653 DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
83654 DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
83655
83656 /*
83657 * Conceptually, we look for the identifier binding by starting from
83658 * 'env' and following to chain of environment records (represented
83659 * by the prototype chain).
83660 *
83661 * If 'env' is NULL, the current activation does not yet have an
83662 * allocated declarative environment record; this should be treated
83663 * exactly as if the environment record existed but had no bindings
83664 * other than register bindings.
83665 *
83666 * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
83667 * the environment will always be initialized immediately; hence
83668 * a NULL 'env' should only happen with the flag set. This is the
83669 * case for: (1) function calls, and (2) strict, direct eval calls.
83670 */
83671
83672 if (env == NULL && act != NULL) {
83673 duk_hobject *func;
83674 duk_hcompfunc *f;
83675
83676 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
83677 "delayed env case, look up activation regs first"));
83678
83679 /*
83680 * Try registers
83681 */
83682
83683 if (duk__getid_activation_regs(thr, name, act, out)) {
83684 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
83685 "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
83686 "(found from register bindings when env=NULL)",
83687 (duk_heaphdr *) name, (duk_tval *) out->value,
83688 (long) out->attrs, (long) out->has_this,
83689 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
83690 return 1;
83691 }
83692
83693 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
83694
83695 /*
83696 * Not found in registers, proceed to the parent record.
83697 * Here we need to determine what the parent would be,
83698 * if 'env' was not NULL (i.e. same logic as when initializing
83699 * the record).
83700 *
83701 * Note that environment initialization is only deferred when
83702 * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
83703 * - Function code
83704 * - Strict eval code
83705 *
83706 * We only need to check _Lexenv here; _Varenv exists only if it
83707 * differs from _Lexenv (and thus _Lexenv will also be present).
83708 */
83709
83710 if (!parents) {
83711 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
83712 "(not found from register bindings when env=NULL)"));
83713 goto fail_not_found;
83714 }
83715
83716 func = DUK_ACT_GET_FUNC(act);
83717 DUK_ASSERT(func != NULL);
83718 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
83719 f = (duk_hcompfunc *) func;
83720
83721 env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
83722 if (!env) {
83723 env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
83724 }
83725
83726 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
83727 (duk_heaphdr *) env));
83728 }
83729
83730 /*
83731 * Prototype walking starting from 'env'.
83732 *
83733 * ('act' is not needed anywhere here.)
83734 */
83735
83736 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
83737 while (env != NULL) {
83738 duk_small_uint_t cl;
83739 duk_uint_t attrs;
83740
83741 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
83742 (duk_heaphdr *) name,
83743 (void *) env,
83744 (duk_heaphdr *) env));
83745
83746 DUK_ASSERT(env != NULL);
83747 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
83748 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
83749
83750 cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
83751 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
83752 if (cl == DUK_HOBJECT_CLASS_DECENV) {
83753 /*
83754 * Declarative environment record.
83755 *
83756 * Identifiers can never be stored in ancestors and are
83757 * always plain values, so we can use an internal helper
83758 * and access the value directly with an duk_tval ptr.
83759 *
83760 * A closed environment is only indicated by it missing
83761 * the "book-keeping" properties required for accessing
83762 * register-bound variables.
83763 */
83764
83765 DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env);
83766 if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) {
83767 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
83768 "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
83769 "(declarative environment record, scope open, found in regs)",
83770 (duk_heaphdr *) name, (duk_tval *) out->value,
83771 (long) out->attrs, (long) out->has_this,
83772 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
83773 return 1;
83774 }
83775
83776 tv = duk_hobject_find_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
83777 if (tv) {
83778 out->value = tv;
83779 out->attrs = attrs;
83780 out->env = env;
83781 out->holder = env;
83782 out->has_this = 0;
83783
83784 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
83785 "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
83786 "(declarative environment record, found in properties)",
83787 (duk_heaphdr *) name, (duk_tval *) out->value,
83788 (long) out->attrs, (long) out->has_this,
83789 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
83790 return 1;
83791 }
83792 } else {
83793 /*
83794 * Object environment record.
83795 *
83796 * Binding (target) object is an external, uncontrolled object.
83797 * Identifier may be bound in an ancestor property, and may be
83798 * an accessor. Target can also be a Proxy which we must support
83799 * here.
83800 */
83801
83802 /* XXX: we could save space by using _Target OR _This. If _Target, assume
83803 * this binding is undefined. If _This, assumes this binding is _This, and
83804 * target is also _This. One property would then be enough.
83805 */
83806
83807 duk_hobject *target;
83808 duk_bool_t found;
83809
83810 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
83811 DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) env);
83812
83813 target = ((duk_hobjenv *) env)->target;
83814 DUK_ASSERT(target != NULL);
83815
83816 /* Target may be a Proxy or property may be an accessor, so we must
83817 * use an actual, Proxy-aware hasprop check here.
83818 *
83819 * out->holder is NOT set to the actual duk_hobject where the
83820 * property is found, but rather the object binding target object.
83821 */
83822
83823#if defined(DUK_USE_ES6_PROXY)
83824 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) {
83825 duk_tval tv_name;
83826 duk_tval tv_target_tmp;
83827
83828 DUK_ASSERT(name != NULL);
83829 DUK_TVAL_SET_STRING(&tv_name, name);
83830 DUK_TVAL_SET_OBJECT(&tv_target_tmp, target);
83831
83832 found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name);
83833 } else
83834#endif /* DUK_USE_ES6_PROXY */
83835 {
83836 /* XXX: duk_hobject_hasprop() would be correct for
83837 * non-Proxy objects too, but it is about ~20-25%
83838 * slower at present so separate code paths for
83839 * Proxy and non-Proxy now.
83840 */
83841 found = duk_hobject_hasprop_raw(thr, target, name);
83842 }
83843
83844 if (found) {
83845 out->value = NULL; /* can't get value, may be accessor */
83846 out->attrs = 0; /* irrelevant when out->value == NULL */
83847 out->env = env;
83848 out->holder = target;
83849 out->has_this = ((duk_hobjenv *) env)->has_this;
83850
83851 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
83852 "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
83853 "(object environment record)",
83854 (duk_heaphdr *) name, (duk_tval *) out->value,
83855 (long) out->attrs, (long) out->has_this,
83856 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
83857 return 1;
83858 }
83859 }
83860
83861 if (!parents) {
83862 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
83863 "(not found from first traversed env)"));
83864 goto fail_not_found;
83865 }
83866
83867 if (DUK_UNLIKELY(sanity-- == 0)) {
83868 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
83869 DUK_WO_NORETURN(return 0;);
83870 }
83871 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
83872 }
83873
83874 /*
83875 * Not found (even in global object)
83876 */
83877
83878 fail_not_found:
83879 return 0;
83880}
83881
83882/*
83883 * HASVAR: check identifier binding from a given environment record
83884 * without traversing its parents.
83885 *
83886 * This primitive is not exposed to user code as such, but is used
83887 * internally for e.g. declaration binding instantiation.
83888 *
83889 * See E5 Sections:
83890 * 10.2.1.1.1 HasBinding(N)
83891 * 10.2.1.2.1 HasBinding(N)
83892 *
83893 * Note: strictness has no bearing on this check. Hence we don't take
83894 * a 'strict' parameter.
83895 */
83896
83897#if 0 /*unused*/
83898DUK_INTERNAL
83899duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
83900 duk_hobject *env,
83901 duk_hstring *name) {
83902 duk__id_lookup_result ref;
83903 duk_bool_t parents;
83904
83905 DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
83906 "(env -> %!dO)",
83907 (void *) thr, (void *) env, (duk_heaphdr *) name,
83908 (duk_heaphdr *) env));
83909
83910 DUK_ASSERT(thr != NULL);
83911 DUK_ASSERT(env != NULL);
83912 DUK_ASSERT(name != NULL);
83913
83914 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
83915 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
83916
83917 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
83918 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
83919
83920 /* lookup results is ignored */
83921 parents = 0;
83922 return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
83923}
83924#endif
83925
83926/*
83927 * GETVAR
83928 *
83929 * See E5 Sections:
83930 * 11.1.2 Identifier Reference
83931 * 10.3.1 Identifier Resolution
83932 * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd]
83933 * 8.7.1 GetValue (V)
83934 * 8.12.1 [[GetOwnProperty]] (P)
83935 * 8.12.2 [[GetProperty]] (P)
83936 * 8.12.3 [[Get]] (P)
83937 *
83938 * If 'throw' is true, always leaves two values on top of stack: [val this].
83939 *
83940 * If 'throw' is false, returns 0 if identifier cannot be resolved, and the
83941 * stack will be unaffected in this case. If identifier is resolved, returns
83942 * 1 and leaves [val this] on top of stack.
83943 *
83944 * Note: the 'strict' flag of a reference returned by GetIdentifierReference
83945 * is ignored by GetValue. Hence we don't take a 'strict' parameter.
83946 *
83947 * The 'throw' flag is needed for implementing 'typeof' for an unreferenced
83948 * identifier. An unreference identifier in other contexts generates a
83949 * ReferenceError.
83950 */
83951
83952DUK_LOCAL
83953duk_bool_t duk__getvar_helper(duk_hthread *thr,
83954 duk_hobject *env,
83955 duk_activation *act,
83956 duk_hstring *name,
83957 duk_bool_t throw_flag) {
83958 duk__id_lookup_result ref;
83959 duk_tval tv_tmp_obj;
83960 duk_tval tv_tmp_key;
83961 duk_bool_t parents;
83962
83963 DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
83964 "(env -> %!dO)",
83965 (void *) thr, (void *) env, (void *) act,
83966 (duk_heaphdr *) name, (duk_heaphdr *) env));
83967
83968 DUK_ASSERT(thr != NULL);
83969 DUK_ASSERT(name != NULL);
83970 /* env and act may be NULL */
83971
83972 DUK_STATS_INC(thr->heap, stats_getvar_all);
83973
83974 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
83975 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
83976
83977 parents = 1; /* follow parent chain */
83978 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
83979 if (ref.value) {
83980 duk_push_tval(thr, ref.value);
83981 duk_push_undefined(thr);
83982 } else {
83983 DUK_ASSERT(ref.holder != NULL);
83984
83985 /* ref.holder is safe across the getprop call (even
83986 * with side effects) because 'env' is reachable and
83987 * ref.holder is a direct heap pointer.
83988 */
83989
83990 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
83991 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
83992 (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */
83993
83994 if (ref.has_this) {
83995 duk_push_hobject(thr, ref.holder);
83996 } else {
83997 duk_push_undefined(thr);
83998 }
83999
84000 /* [value this] */
84001 }
84002
84003 return 1;
84004 } else {
84005 if (throw_flag) {
84006 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
84007 "identifier '%s' undefined",
84008 (const char *) DUK_HSTRING_GET_DATA(name));
84009 DUK_WO_NORETURN(return 0;);
84010 }
84011
84012 return 0;
84013 }
84014}
84015
84016DUK_INTERNAL
84017duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
84018 duk_hobject *env,
84019 duk_hstring *name,
84020 duk_bool_t throw_flag) {
84021 return duk__getvar_helper(thr, env, NULL, name, throw_flag);
84022}
84023
84024DUK_INTERNAL
84025duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
84026 duk_activation *act,
84027 duk_hstring *name,
84028 duk_bool_t throw_flag) {
84029 DUK_ASSERT(act != NULL);
84030 return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
84031}
84032
84033/*
84034 * PUTVAR
84035 *
84036 * See E5 Sections:
84037 * 11.1.2 Identifier Reference
84038 * 10.3.1 Identifier Resolution
84039 * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd]
84040 * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode]
84041 * 8.12.4 [[CanPut]] (P)
84042 * 8.12.5 [[Put]] (P)
84043 *
84044 * Note: may invalidate any valstack (or object) duk_tval pointers because
84045 * putting a value may reallocate any object or any valstack. Caller beware.
84046 */
84047
84048DUK_LOCAL
84049void duk__putvar_helper(duk_hthread *thr,
84050 duk_hobject *env,
84051 duk_activation *act,
84052 duk_hstring *name,
84053 duk_tval *val,
84054 duk_bool_t strict) {
84055 duk__id_lookup_result ref;
84056 duk_tval tv_tmp_val;
84057 duk_tval tv_tmp_obj;
84058 duk_tval tv_tmp_key;
84059 duk_bool_t parents;
84060
84061 DUK_STATS_INC(thr->heap, stats_putvar_all);
84062
84063 DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
84064 "(env -> %!dO, val -> %!T)",
84065 (void *) thr, (void *) env, (void *) act,
84066 (duk_heaphdr *) name, (void *) val, (long) strict,
84067 (duk_heaphdr *) env, (duk_tval *) val));
84068
84069 DUK_ASSERT(thr != NULL);
84070 DUK_ASSERT(name != NULL);
84071 DUK_ASSERT(val != NULL);
84072 /* env and act may be NULL */
84073
84074 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
84075 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
84076 DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
84077
84078 DUK_TVAL_SET_TVAL(&tv_tmp_val, val); /* Stabilize. */
84079 val = NULL;
84080
84081 /*
84082 * In strict mode E5 protects 'eval' and 'arguments' from being
84083 * assigned to (or even declared anywhere). Attempt to do so
84084 * should result in a compile time SyntaxError. See the internal
84085 * design documentation for details.
84086 *
84087 * Thus, we should never come here, run-time, for strict code,
84088 * and name 'eval' or 'arguments'.
84089 */
84090
84091 DUK_ASSERT(!strict ||
84092 (name != DUK_HTHREAD_STRING_EVAL(thr) &&
84093 name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
84094
84095 /*
84096 * Lookup variable and update in-place if found.
84097 */
84098
84099 parents = 1; /* follow parent chain */
84100
84101 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
84102 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
84103 /* Update duk_tval in-place if pointer provided and the
84104 * property is writable. If the property is not writable
84105 * (immutable binding), use duk_hobject_putprop() which
84106 * will respect mutability.
84107 */
84108 duk_tval *tv_val;
84109
84110 tv_val = ref.value;
84111 DUK_ASSERT(tv_val != NULL);
84112 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, &tv_tmp_val); /* side effects */
84113
84114 /* ref.value invalidated here */
84115 } else {
84116 DUK_ASSERT(ref.holder != NULL);
84117
84118 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
84119 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
84120 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, strict);
84121
84122 /* ref.value invalidated here */
84123 }
84124
84125 return;
84126 }
84127
84128 /*
84129 * Not found: write to global object (non-strict) or ReferenceError
84130 * (strict); see E5 Section 8.7.2, step 3.
84131 */
84132
84133 if (strict) {
84134 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
84135 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
84136 "identifier '%s' undefined",
84137 (const char *) DUK_HSTRING_GET_DATA(name));
84138 DUK_WO_NORETURN(return;);
84139 }
84140
84141 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
84142
84143 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
84144 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
84145 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, 0); /* 0 = no throw */
84146
84147 /* NB: 'val' may be invalidated here because put_value may realloc valstack,
84148 * caller beware.
84149 */
84150}
84151
84152DUK_INTERNAL
84153void duk_js_putvar_envrec(duk_hthread *thr,
84154 duk_hobject *env,
84155 duk_hstring *name,
84156 duk_tval *val,
84157 duk_bool_t strict) {
84158 duk__putvar_helper(thr, env, NULL, name, val, strict);
84159}
84160
84161DUK_INTERNAL
84162void duk_js_putvar_activation(duk_hthread *thr,
84163 duk_activation *act,
84164 duk_hstring *name,
84165 duk_tval *val,
84166 duk_bool_t strict) {
84167 DUK_ASSERT(act != NULL);
84168 duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
84169}
84170
84171/*
84172 * DELVAR
84173 *
84174 * See E5 Sections:
84175 * 11.4.1 The delete operator
84176 * 10.2.1.1.5 DeleteBinding (N) [declarative environment record]
84177 * 10.2.1.2.5 DeleteBinding (N) [object environment record]
84178 *
84179 * Variable bindings established inside eval() are deletable (configurable),
84180 * other bindings are not, including variables declared in global level.
84181 * Registers are always non-deletable, and the deletion of other bindings
84182 * is controlled by the configurable flag.
84183 *
84184 * For strict mode code, the 'delete' operator should fail with a compile
84185 * time SyntaxError if applied to identifiers. Hence, no strict mode
84186 * run-time deletion of identifiers should ever happen. This function
84187 * should never be called from strict mode code!
84188 */
84189
84190DUK_LOCAL
84191duk_bool_t duk__delvar_helper(duk_hthread *thr,
84192 duk_hobject *env,
84193 duk_activation *act,
84194 duk_hstring *name) {
84195 duk__id_lookup_result ref;
84196 duk_bool_t parents;
84197
84198 DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
84199 "(env -> %!dO)",
84200 (void *) thr, (void *) env, (void *) act,
84201 (duk_heaphdr *) name, (duk_heaphdr *) env));
84202
84203 DUK_ASSERT(thr != NULL);
84204 DUK_ASSERT(name != NULL);
84205 /* env and act may be NULL */
84206
84207 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
84208
84209 parents = 1; /* follow parent chain */
84210
84211 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
84212 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
84213 /* Identifier found in registers (always non-deletable)
84214 * or declarative environment record and non-configurable.
84215 */
84216 return 0;
84217 }
84218 DUK_ASSERT(ref.holder != NULL);
84219
84220 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
84221 }
84222
84223 /*
84224 * Not found (even in global object).
84225 *
84226 * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
84227 * step 3.b. In strict mode this case is a compile time SyntaxError so
84228 * we should not come here.
84229 */
84230
84231 DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
84232 "(treated as silent success)",
84233 (duk_heaphdr *) name));
84234 return 1;
84235}
84236
84237#if 0 /*unused*/
84238DUK_INTERNAL
84239duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
84240 duk_hobject *env,
84241 duk_hstring *name) {
84242 return duk__delvar_helper(thr, env, NULL, name);
84243}
84244#endif
84245
84246DUK_INTERNAL
84247duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
84248 duk_activation *act,
84249 duk_hstring *name) {
84250 DUK_ASSERT(act != NULL);
84251 return duk__delvar_helper(thr, act->lex_env, act, name);
84252}
84253
84254/*
84255 * DECLVAR
84256 *
84257 * See E5 Sections:
84258 * 10.4.3 Entering Function Code
84259 * 10.5 Declaration Binding Instantion
84260 * 12.2 Variable Statement
84261 * 11.1.2 Identifier Reference
84262 * 10.3.1 Identifier Resolution
84263 *
84264 * Variable declaration behavior is mainly discussed in Section 10.5,
84265 * and is not discussed in the execution semantics (Sections 11-13).
84266 *
84267 * Conceptually declarations happen when code (global, eval, function)
84268 * is entered, before any user code is executed. In practice, register-
84269 * bound identifiers are 'declared' automatically (by virtue of being
84270 * allocated to registers with the initial value 'undefined'). Other
84271 * identifiers are declared in the function prologue with this primitive.
84272 *
84273 * Since non-register bindings eventually back to an internal object's
84274 * properties, the 'prop_flags' argument is used to specify binding
84275 * type:
84276 *
84277 * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
84278 * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
84279 * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
84280 * doesn't really matter for internal objects
84281 *
84282 * All bindings are non-deletable mutable bindings except:
84283 *
84284 * - Declarations in eval code (mutable, deletable)
84285 * - 'arguments' binding in strict function code (immutable)
84286 * - Function name binding of a function expression (immutable)
84287 *
84288 * Declarations may go to declarative environment records (always
84289 * so for functions), but may also go to object environment records
84290 * (e.g. global code). The global object environment has special
84291 * behavior when re-declaring a function (but not a variable); see
84292 * E5.1 specification, Section 10.5, step 5.e.
84293 *
84294 * Declarations always go to the 'top-most' environment record, i.e.
84295 * we never check the record chain. It's not an error even if a
84296 * property (even an immutable or non-deletable one) of the same name
84297 * already exists.
84298 *
84299 * If a declared variable already exists, its value needs to be updated
84300 * (if possible). Returns 1 if a PUTVAR needs to be done by the caller;
84301 * otherwise returns 0.
84302 */
84303
84304DUK_LOCAL
84305duk_bool_t duk__declvar_helper(duk_hthread *thr,
84306 duk_hobject *env,
84307 duk_hstring *name,
84308 duk_tval *val,
84309 duk_small_uint_t prop_flags,
84310 duk_bool_t is_func_decl) {
84311 duk_hobject *holder;
84312 duk_bool_t parents;
84313 duk__id_lookup_result ref;
84314 duk_tval *tv;
84315
84316 DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
84317 "(env -> %!iO)",
84318 (void *) thr, (void *) env, (duk_heaphdr *) name,
84319 (duk_tval *) val, (unsigned long) prop_flags,
84320 (unsigned int) is_func_decl, (duk_heaphdr *) env));
84321
84322 DUK_ASSERT(thr != NULL);
84323 DUK_ASSERT(env != NULL);
84324 DUK_ASSERT(name != NULL);
84325 DUK_ASSERT(val != NULL);
84326
84327 /* Note: in strict mode the compiler should reject explicit
84328 * declaration of 'eval' or 'arguments'. However, internal
84329 * bytecode may declare 'arguments' in the function prologue.
84330 * We don't bother checking (or asserting) for these now.
84331 */
84332
84333 /* Note: val is a stable duk_tval pointer. The caller makes
84334 * a value copy into its stack frame, so 'tv_val' is not subject
84335 * to side effects here.
84336 */
84337
84338 /*
84339 * Check whether already declared.
84340 *
84341 * We need to check whether the binding exists in the environment
84342 * without walking its parents. However, we still need to check
84343 * register-bound identifiers and the prototype chain of an object
84344 * environment target object.
84345 */
84346
84347 parents = 0; /* just check 'env' */
84348 if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
84349 duk_int_t e_idx;
84350 duk_int_t h_idx;
84351 duk_small_uint_t flags;
84352
84353 /*
84354 * Variable already declared, ignore re-declaration.
84355 * The only exception is the updated behavior of E5.1 for
84356 * global function declarations, E5.1 Section 10.5, step 5.e.
84357 * This behavior does not apply to global variable declarations.
84358 */
84359
84360 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
84361 DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
84362 return 1; /* 1 -> needs a PUTVAR */
84363 }
84364
84365 /*
84366 * Special behavior in E5.1.
84367 *
84368 * Note that even though parents == 0, the conflicting property
84369 * may be an inherited property (currently our global object's
84370 * prototype is Object.prototype). Step 5.e first operates on
84371 * the existing property (which is potentially in an ancestor)
84372 * and then defines a new property in the global object (and
84373 * never modifies the ancestor).
84374 *
84375 * Also note that this logic would become even more complicated
84376 * if the conflicting property might be a virtual one. Object
84377 * prototype has no virtual properties, though.
84378 *
84379 * XXX: this is now very awkward, rework.
84380 */
84381
84382 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
84383 "updated E5.1 processing"));
84384
84385 DUK_ASSERT(ref.holder != NULL);
84386 holder = ref.holder;
84387
84388 /* holder will be set to the target object, not the actual object
84389 * where the property was found (see duk__get_identifier_reference()).
84390 */
84391 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
84392 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
84393
84394 /* XXX: use a helper for prototype traversal; no loop check here */
84395 /* must be found: was found earlier, and cannot be inherited */
84396 for (;;) {
84397 DUK_ASSERT(holder != NULL);
84398 if (duk_hobject_find_entry(thr->heap, holder, name, &e_idx, &h_idx)) {
84399 DUK_ASSERT(e_idx >= 0);
84400 break;
84401 }
84402 /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
84403 * asserted above.
84404 */
84405 holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
84406 }
84407 DUK_ASSERT(holder != NULL);
84408 DUK_ASSERT(e_idx >= 0);
84409 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
84410 * below; it never actually triggers because holder is actually never
84411 * NULL.
84412 */
84413
84414 /* ref.holder is global object, holder is the object with the
84415 * conflicting property.
84416 */
84417
84418 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
84419 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
84420 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
84421 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
84422 "accessor -> reject"));
84423 goto fail_existing_attributes;
84424 }
84425 if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
84426 (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
84427 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
84428 "plain property which is not writable and "
84429 "enumerable -> reject"));
84430 goto fail_existing_attributes;
84431 }
84432
84433 DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
84434 "is plain, enumerable, and writable -> "
84435 "allow redeclaration"));
84436 }
84437
84438 if (holder == ref.holder) {
84439 /* XXX: if duk_hobject_define_property_internal() was updated
84440 * to handle a pre-existing accessor property, this would be
84441 * a simple call (like for the ancestor case).
84442 */
84443 DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
84444
84445 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
84446 duk_hobject *tmp;
84447
84448 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
84449 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
84450 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
84451 DUK_UNREF(tmp);
84452 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
84453 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
84454 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
84455 DUK_UNREF(tmp);
84456 } else {
84457 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
84458 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
84459 }
84460
84461 /* Here val would be potentially invalid if we didn't make
84462 * a value copy at the caller.
84463 */
84464
84465 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
84466 DUK_TVAL_SET_TVAL(tv, val);
84467 DUK_TVAL_INCREF(thr, tv);
84468 DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
84469
84470 DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
84471 "value -> %!T, prop_flags=0x%08lx",
84472 (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
84473 (unsigned long) prop_flags));
84474 } else {
84475 DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
84476
84477 DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
84478 duk_push_tval(thr, val);
84479 duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
84480 }
84481
84482 return 0;
84483 }
84484
84485 /*
84486 * Not found (in registers or record objects). Declare
84487 * to current variable environment.
84488 */
84489
84490 /*
84491 * Get holder object
84492 */
84493
84494 if (DUK_HOBJECT_IS_DECENV(env)) {
84495 DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env);
84496 holder = env;
84497 } else {
84498 DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) env);
84499 holder = ((duk_hobjenv *) env)->target;
84500 DUK_ASSERT(holder != NULL);
84501 }
84502
84503 /*
84504 * Define new property
84505 *
84506 * Note: this may fail if the holder is not extensible.
84507 */
84508
84509 /* XXX: this is awkward as we use an internal method which doesn't handle
84510 * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
84511 * or Object.defineProperty() here.
84512 */
84513
84514 if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
84515 goto fail_not_extensible;
84516 }
84517
84518 duk_push_hobject(thr, holder);
84519 duk_push_hstring(thr, name);
84520 duk_push_tval(thr, val);
84521 duk_xdef_prop(thr, -3, prop_flags); /* [holder name val] -> [holder] */
84522 duk_pop_unsafe(thr);
84523
84524 return 0;
84525
84526 fail_existing_attributes:
84527 fail_not_extensible:
84528 DUK_ERROR_TYPE(thr, "declaration failed");
84529 DUK_WO_NORETURN(return 0;);
84530}
84531
84532DUK_INTERNAL
84533duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
84534 duk_activation *act,
84535 duk_hstring *name,
84536 duk_tval *val,
84537 duk_small_uint_t prop_flags,
84538 duk_bool_t is_func_decl) {
84539 duk_hobject *env;
84540 duk_tval tv_val_copy;
84541
84542 DUK_ASSERT(act != NULL);
84543
84544 /*
84545 * Make a value copy of the input val. This ensures that
84546 * side effects cannot invalidate the pointer.
84547 */
84548
84549 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
84550 val = &tv_val_copy;
84551
84552 /*
84553 * Delayed env creation check
84554 */
84555
84556 if (!act->var_env) {
84557 DUK_ASSERT(act->lex_env == NULL);
84558 duk_js_init_activation_environment_records_delayed(thr, act);
84559 /* 'act' is a stable pointer, so still OK. */
84560 }
84561 DUK_ASSERT(act->lex_env != NULL);
84562 DUK_ASSERT(act->var_env != NULL);
84563
84564 env = act->var_env;
84565 DUK_ASSERT(env != NULL);
84566 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
84567
84568 return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
84569}
84570#line 1 "duk_lexer.c"
84571/*
84572 * Lexer for source files, ToNumber() string conversions, RegExp expressions,
84573 * and JSON.
84574 *
84575 * Provides a stream of ECMAScript tokens from an UTF-8/CESU-8 buffer. The
84576 * caller can also rewind the token stream into a certain position which is
84577 * needed by the compiler part for multi-pass scanning. Tokens are
84578 * represented as duk_token structures, and contain line number information.
84579 * Token types are identified with DUK_TOK_* defines.
84580 *
84581 * Characters are decoded into a fixed size lookup window consisting of
84582 * decoded Unicode code points, with window positions past the end of the
84583 * input filled with an invalid codepoint (-1). The tokenizer can thus
84584 * perform multiple character lookups efficiently and with few sanity
84585 * checks (such as access outside the end of the input), which keeps the
84586 * tokenization code small at the cost of performance.
84587 *
84588 * Character data in tokens, such as identifier names and string literals,
84589 * is encoded into CESU-8 format on-the-fly while parsing the token in
84590 * question. The string data is made reachable to garbage collection by
84591 * placing the token-related values in value stack entries allocated for
84592 * this purpose by the caller. The characters exist in Unicode code point
84593 * form only in the fixed size lookup window, which keeps character data
84594 * expansion (of especially ASCII data) low.
84595 *
84596 * Token parsing supports the full range of Unicode characters as described
84597 * in the E5 specification. Parsing has been optimized for ASCII characters
84598 * because ordinary ECMAScript code consists almost entirely of ASCII
84599 * characters. Matching of complex Unicode codepoint sets (such as in the
84600 * IdentifierStart and IdentifierPart productions) is optimized for size,
84601 * and is done using a linear scan of a bit-packed list of ranges. This is
84602 * very slow, but should never be entered unless the source code actually
84603 * contains Unicode characters.
84604 *
84605 * ECMAScript tokenization is partially context sensitive. First,
84606 * additional future reserved words are recognized in strict mode (see E5
84607 * Section 7.6.1.2). Second, a forward slash character ('/') can be
84608 * recognized either as starting a RegExp literal or as a division operator,
84609 * depending on context. The caller must provide necessary context flags
84610 * when requesting a new token.
84611 *
84612 * Future work:
84613 *
84614 * * Make line number tracking optional, as it consumes space.
84615 *
84616 * * Add a feature flag for disabling UTF-8 decoding of input, as most
84617 * source code is ASCII. Because of Unicode escapes written in ASCII,
84618 * this does not allow Unicode support to be removed from e.g.
84619 * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
84620 * encoding of e.g. string literals.
84621 *
84622 * * Add a feature flag for disabling Unicode compliance of e.g. identifier
84623 * names. This allows for a build more than a kilobyte smaller, because
84624 * Unicode ranges needed by duk_unicode_is_identifier_start() and
84625 * duk_unicode_is_identifier_part() can be dropped. String literals
84626 * should still be allowed to contain escaped Unicode, so this still does
84627 * not allow removal of CESU-8 encoding of e.g. string literals.
84628 *
84629 * * Character lookup tables for codepoints above BMP could be stripped.
84630 *
84631 * * Strictly speaking, E5 specification requires that source code consists
84632 * of 16-bit code units, and if not, must be conceptually converted to
84633 * that format first. The current lexer processes Unicode code points
84634 * and allows characters outside the BMP. These should be converted to
84635 * surrogate pairs while reading the source characters into the window,
84636 * not after tokens have been formed (as is done now). However, the fix
84637 * is not trivial because two characters are decoded from one codepoint.
84638 *
84639 * * Optimize for speed as well as size. Large if-else ladders are (at
84640 * least potentially) slow.
84641 */
84642
84643/* #include duk_internal.h -> already included */
84644
84645/*
84646 * Various defines and file specific helper macros
84647 */
84648
84649#define DUK__MAX_RE_DECESC_DIGITS 9
84650#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
84651
84652/* whether to use macros or helper function depends on call count */
84653#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
84654#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x))
84655#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
84656#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
84657#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
84658
84659/* lexer character window helpers */
84660#define DUK__LOOKUP(lex_ctx,idx) ((lex_ctx)->window[(idx)].codepoint)
84661#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_chars((lex_ctx), (count))
84662#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
84663#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
84664#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
84665#define DUK__APPENDBUFFER_ASCII(lex_ctx,x) duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x))
84666
84667/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
84668#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
84669#define DUK__L1() DUK__LOOKUP(lex_ctx, 1)
84670#define DUK__L2() DUK__LOOKUP(lex_ctx, 2)
84671#define DUK__L3() DUK__LOOKUP(lex_ctx, 3)
84672#define DUK__L4() DUK__LOOKUP(lex_ctx, 4)
84673#define DUK__L5() DUK__LOOKUP(lex_ctx, 5)
84674
84675/* packed advance/token number macro used by multiple functions */
84676#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
84677
84678/*
84679 * Advance lookup window by N characters, filling in new characters as
84680 * necessary. After returning caller is guaranteed a character window of
84681 * at least DUK_LEXER_WINDOW_SIZE characters.
84682 *
84683 * The main function duk__advance_bytes() is called at least once per every
84684 * token so it has a major lexer/compiler performance impact. There are two
84685 * variants for the main duk__advance_bytes() algorithm: a sliding window
84686 * approach which is slightly faster at the cost of larger code footprint,
84687 * and a simple copying one.
84688 *
84689 * Decoding directly from the source string would be another lexing option.
84690 * But the lookup window based approach has the advantage of hiding the
84691 * source string and its encoding effectively which gives more flexibility
84692 * going forward to e.g. support chunked streaming of source from flash.
84693 *
84694 * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
84695 * U+10FFFF, causing an error if the input is unparseable. Leniency means:
84696 *
84697 * * Unicode code point validation is intentionally not performed,
84698 * except to check that the codepoint does not exceed 0x10ffff.
84699 *
84700 * * In particular, surrogate pairs are allowed and not combined, which
84701 * allows source files to represent all SourceCharacters with CESU-8.
84702 * Broken surrogate pairs are allowed, as ECMAScript does not mandate
84703 * their validation.
84704 *
84705 * * Allow non-shortest UTF-8 encodings.
84706 *
84707 * Leniency here causes few security concerns because all character data is
84708 * decoded into Unicode codepoints before lexer processing, and is then
84709 * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with
84710 * a compiler option. However, ECMAScript source characters include -all-
84711 * 16-bit unsigned integer codepoints, so leniency seems to be appropriate.
84712 *
84713 * Note that codepoints above the BMP are not strictly SourceCharacters,
84714 * but the lexer still accepts them as such. Before ending up in a string
84715 * or an identifier name, codepoints above BMP are converted into surrogate
84716 * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
84717 * expected by ECMAScript.
84718 *
84719 * An alternative approach to dealing with invalid or partial sequences
84720 * would be to skip them and replace them with e.g. the Unicode replacement
84721 * character U+FFFD. This has limited utility because a replacement character
84722 * will most likely cause a parse error, unless it occurs inside a string.
84723 * Further, ECMAScript source is typically pure ASCII.
84724 *
84725 * See:
84726 *
84727 * http://en.wikipedia.org/wiki/UTF-8
84728 * http://en.wikipedia.org/wiki/CESU-8
84729 * http://tools.ietf.org/html/rfc3629
84730 * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
84731 *
84732 * Future work:
84733 *
84734 * * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
84735 * in strict UTF-8 mode.
84736 *
84737 * * Size optimize. An attempt to use a 16-byte lookup table for the first
84738 * byte resulted in a code increase though.
84739 *
84740 * * Is checking against maximum 0x10ffff really useful? 4-byte encoding
84741 * imposes a certain limit anyway.
84742 *
84743 * * Support chunked streaming of source code. Can be implemented either
84744 * by streaming chunks of bytes or chunks of codepoints.
84745 */
84746
84747#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
84748DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
84749 duk_lexer_codepoint *cp, *cp_end;
84750 duk_ucodepoint_t x;
84751 duk_small_uint_t contlen;
84752 const duk_uint8_t *p, *p_end;
84753#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84754 duk_ucodepoint_t mincp;
84755#endif
84756 duk_int_t input_line;
84757
84758 /* Use temporaries and update lex_ctx only when finished. */
84759 input_line = lex_ctx->input_line;
84760 p = lex_ctx->input + lex_ctx->input_offset;
84761 p_end = lex_ctx->input + lex_ctx->input_length;
84762
84763 cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
84764 cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
84765
84766 for (; cp != cp_end; cp++) {
84767 cp->offset = (duk_size_t) (p - lex_ctx->input);
84768 cp->line = input_line;
84769
84770 /* XXX: potential issue with signed pointers, p_end < p. */
84771 if (DUK_UNLIKELY(p >= p_end)) {
84772 /* If input_offset were assigned a negative value, it would
84773 * result in a large positive value. Most likely it would be
84774 * larger than input_length and be caught here. In any case
84775 * no memory unsafe behavior would happen.
84776 */
84777 cp->codepoint = -1;
84778 continue;
84779 }
84780
84781 x = (duk_ucodepoint_t) (*p++);
84782
84783 /* Fast path. */
84784
84785 if (DUK_LIKELY(x < 0x80UL)) {
84786 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
84787 if (DUK_UNLIKELY(x <= 0x000dUL)) {
84788 if ((x == 0x000aUL) ||
84789 ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
84790 /* lookup for 0x000a above assumes shortest encoding now */
84791
84792 /* E5 Section 7.3, treat the following as newlines:
84793 * LF
84794 * CR [not followed by LF]
84795 * LS
84796 * PS
84797 *
84798 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
84799 * the line number.
84800 */
84801 input_line++;
84802 }
84803 }
84804
84805 cp->codepoint = (duk_codepoint_t) x;
84806 continue;
84807 }
84808
84809 /* Slow path. */
84810
84811 if (x < 0xc0UL) {
84812 /* 10xx xxxx -> invalid */
84813 goto error_encoding;
84814 } else if (x < 0xe0UL) {
84815 /* 110x xxxx 10xx xxxx */
84816 contlen = 1;
84817#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84818 mincp = 0x80UL;
84819#endif
84820 x = x & 0x1fUL;
84821 } else if (x < 0xf0UL) {
84822 /* 1110 xxxx 10xx xxxx 10xx xxxx */
84823 contlen = 2;
84824#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84825 mincp = 0x800UL;
84826#endif
84827 x = x & 0x0fUL;
84828 } else if (x < 0xf8UL) {
84829 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
84830 contlen = 3;
84831#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84832 mincp = 0x10000UL;
84833#endif
84834 x = x & 0x07UL;
84835 } else {
84836 /* no point in supporting encodings of 5 or more bytes */
84837 goto error_encoding;
84838 }
84839
84840 DUK_ASSERT(p_end >= p);
84841 if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
84842 goto error_clipped;
84843 }
84844
84845 while (contlen > 0) {
84846 duk_small_uint_t y;
84847 y = *p++;
84848 if ((y & 0xc0U) != 0x80U) {
84849 /* check that byte has the form 10xx xxxx */
84850 goto error_encoding;
84851 }
84852 x = x << 6;
84853 x += y & 0x3fUL;
84854 contlen--;
84855 }
84856
84857 /* check final character validity */
84858
84859 if (x > 0x10ffffUL) {
84860 goto error_encoding;
84861 }
84862#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84863 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
84864 goto error_encoding;
84865 }
84866#endif
84867
84868 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
84869 if ((x == 0x2028UL) || (x == 0x2029UL)) {
84870 input_line++;
84871 }
84872
84873 cp->codepoint = (duk_codepoint_t) x;
84874 }
84875
84876 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
84877 lex_ctx->input_line = input_line;
84878 return;
84879
84880 error_clipped: /* clipped codepoint */
84881 error_encoding: /* invalid codepoint encoding or codepoint */
84882 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
84883 lex_ctx->input_line = input_line;
84884
84885 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
84886 DUK_WO_NORETURN(return;);
84887}
84888
84889DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
84890 duk_small_uint_t used_bytes, avail_bytes;
84891
84892 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
84893 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
84894 DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
84895 DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
84896 DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
84897
84898 /* Zero 'count' is also allowed to make call sites easier.
84899 * Arithmetic in bytes generates better code in GCC.
84900 */
84901
84902 lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */
84903 used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
84904 avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
84905 if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
84906 /* Not enough data to provide a full window, so "scroll" window to
84907 * start of buffer and fill up the rest.
84908 */
84909 duk_memmove((void *) lex_ctx->buffer,
84910 (const void *) lex_ctx->window,
84911 (size_t) avail_bytes);
84912 lex_ctx->window = lex_ctx->buffer;
84913 duk__fill_lexer_buffer(lex_ctx, avail_bytes);
84914 }
84915}
84916
84917DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
84918 lex_ctx->window = lex_ctx->buffer;
84919 duk__fill_lexer_buffer(lex_ctx, 0);
84920}
84921#else /* DUK_USE_LEXER_SLIDING_WINDOW */
84922DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
84923 duk_ucodepoint_t x;
84924 duk_small_uint_t len;
84925 duk_small_uint_t i;
84926 const duk_uint8_t *p;
84927#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84928 duk_ucodepoint_t mincp;
84929#endif
84930 duk_size_t input_offset;
84931
84932 input_offset = lex_ctx->input_offset;
84933 if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
84934 /* If input_offset were assigned a negative value, it would
84935 * result in a large positive value. Most likely it would be
84936 * larger than input_length and be caught here. In any case
84937 * no memory unsafe behavior would happen.
84938 */
84939 return -1;
84940 }
84941
84942 p = lex_ctx->input + input_offset;
84943 x = (duk_ucodepoint_t) (*p);
84944
84945 if (DUK_LIKELY(x < 0x80UL)) {
84946 /* 0xxx xxxx -> fast path */
84947
84948 /* input offset tracking */
84949 lex_ctx->input_offset++;
84950
84951 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
84952 if (DUK_UNLIKELY(x <= 0x000dUL)) {
84953 if ((x == 0x000aUL) ||
84954 ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
84955 lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
84956 /* lookup for 0x000a above assumes shortest encoding now */
84957
84958 /* E5 Section 7.3, treat the following as newlines:
84959 * LF
84960 * CR [not followed by LF]
84961 * LS
84962 * PS
84963 *
84964 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
84965 * the line number.
84966 */
84967 lex_ctx->input_line++;
84968 }
84969 }
84970
84971 return (duk_codepoint_t) x;
84972 }
84973
84974 /* Slow path. */
84975
84976 if (x < 0xc0UL) {
84977 /* 10xx xxxx -> invalid */
84978 goto error_encoding;
84979 } else if (x < 0xe0UL) {
84980 /* 110x xxxx 10xx xxxx */
84981 len = 2;
84982#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84983 mincp = 0x80UL;
84984#endif
84985 x = x & 0x1fUL;
84986 } else if (x < 0xf0UL) {
84987 /* 1110 xxxx 10xx xxxx 10xx xxxx */
84988 len = 3;
84989#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84990 mincp = 0x800UL;
84991#endif
84992 x = x & 0x0fUL;
84993 } else if (x < 0xf8UL) {
84994 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
84995 len = 4;
84996#if defined(DUK_USE_STRICT_UTF8_SOURCE)
84997 mincp = 0x10000UL;
84998#endif
84999 x = x & 0x07UL;
85000 } else {
85001 /* no point in supporting encodings of 5 or more bytes */
85002 goto error_encoding;
85003 }
85004
85005 DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
85006 if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
85007 goto error_clipped;
85008 }
85009
85010 p++;
85011 for (i = 1; i < len; i++) {
85012 duk_small_uint_t y;
85013 y = *p++;
85014 if ((y & 0xc0U) != 0x80U) {
85015 /* check that byte has the form 10xx xxxx */
85016 goto error_encoding;
85017 }
85018 x = x << 6;
85019 x += y & 0x3fUL;
85020 }
85021
85022 /* check final character validity */
85023
85024 if (x > 0x10ffffUL) {
85025 goto error_encoding;
85026 }
85027#if defined(DUK_USE_STRICT_UTF8_SOURCE)
85028 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
85029 goto error_encoding;
85030 }
85031#endif
85032
85033 /* input offset tracking */
85034 lex_ctx->input_offset += len;
85035
85036 /* line tracking */
85037 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
85038 if ((x == 0x2028UL) || (x == 0x2029UL)) {
85039 lex_ctx->input_line++;
85040 }
85041
85042 return (duk_codepoint_t) x;
85043
85044 error_clipped: /* clipped codepoint */
85045 error_encoding: /* invalid codepoint encoding or codepoint */
85046 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
85047 DUK_WO_NORETURN(return 0;);
85048}
85049
85050DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
85051 duk_small_uint_t keep_bytes;
85052 duk_lexer_codepoint *cp, *cp_end;
85053
85054 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
85055 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
85056
85057 /* Zero 'count' is also allowed to make call sites easier. */
85058
85059 keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
85060 duk_memmove((void *) lex_ctx->window,
85061 (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
85062 (size_t) keep_bytes);
85063
85064 cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
85065 cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
85066 for (; cp != cp_end; cp++) {
85067 cp->offset = lex_ctx->input_offset;
85068 cp->line = lex_ctx->input_line;
85069 cp->codepoint = duk__read_char(lex_ctx);
85070 }
85071}
85072
85073DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
85074 /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
85075 duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */
85076}
85077#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
85078
85079DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) {
85080 duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint));
85081}
85082
85083/*
85084 * (Re)initialize the temporary byte buffer. May be called extra times
85085 * with little impact.
85086 */
85087
85088DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
85089 /* Reuse buffer as is unless buffer has grown large. */
85090 if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
85091 /* Keep current size */
85092 } else {
85093 duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
85094 }
85095
85096 DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
85097}
85098
85099/*
85100 * Append a Unicode codepoint to the temporary byte buffer. Performs
85101 * CESU-8 surrogate pair encoding for codepoints above the BMP.
85102 * Existing surrogate pairs are allowed and also encoded into CESU-8.
85103 */
85104
85105DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
85106 /*
85107 * Since character data is only generated by decoding the source or by
85108 * the compiler itself, we rely on the input codepoints being correct
85109 * and avoid a check here.
85110 *
85111 * Character data can also come here through decoding of Unicode
85112 * escapes ("\udead\ubeef") so all 16-but unsigned values can be
85113 * present, even when the source file itself is strict UTF-8.
85114 */
85115 DUK_ASSERT(x >= 0 && x <= 0x10ffffL);
85116
85117 DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
85118}
85119
85120DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
85121 /* ASCII characters can be emitted as a single byte without encoding
85122 * which matters for some fast paths.
85123 */
85124 DUK_ASSERT(x >= 0 && x <= 0x7f);
85125
85126 DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x);
85127}
85128
85129/*
85130 * Intern the temporary byte buffer into a valstack slot
85131 * (in practice, slot1 or slot2).
85132 */
85133
85134DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
85135 DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
85136
85137 DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
85138 duk_replace(lex_ctx->thr, valstack_idx);
85139 return duk_known_hstring(lex_ctx->thr, valstack_idx);
85140}
85141
85142/*
85143 * Init lexer context
85144 */
85145
85146DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
85147 DUK_ASSERT(lex_ctx != NULL);
85148
85149 duk_memzero(lex_ctx, sizeof(*lex_ctx));
85150#if defined(DUK_USE_EXPLICIT_NULL_INIT)
85151#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
85152 lex_ctx->window = NULL;
85153#endif
85154 lex_ctx->thr = NULL;
85155 lex_ctx->input = NULL;
85156 lex_ctx->buf = NULL;
85157#endif
85158}
85159
85160/*
85161 * Set lexer input position and reinitialize lookup window.
85162 */
85163
85164DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
85165 pt->offset = lex_ctx->window[0].offset;
85166 pt->line = lex_ctx->window[0].line;
85167}
85168
85169DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
85170 DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
85171 DUK_ASSERT(pt->line >= 1);
85172 lex_ctx->input_offset = pt->offset;
85173 lex_ctx->input_line = pt->line;
85174 duk__init_lexer_window(lex_ctx);
85175}
85176
85177/*
85178 * Lexing helpers
85179 */
85180
85181/* Numeric value of a hex digit (also covers octal and decimal digits) or
85182 * -1 if not a valid hex digit.
85183 */
85184DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) {
85185 duk_small_int_t t;
85186
85187 /* Here 'x' is a Unicode codepoint */
85188 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
85189 t = duk_hex_dectab[x];
85190 if (DUK_LIKELY(t >= 0)) {
85191 return t;
85192 }
85193 }
85194
85195 return -1;
85196}
85197
85198/* Just a wrapper for call sites where 'x' is known to be valid so
85199 * we assert for it before decoding.
85200 */
85201DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) {
85202 duk_codepoint_t ret;
85203
85204 DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
85205 (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) ||
85206 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F));
85207 ret = duk__hexval_validate(x);
85208 DUK_ASSERT(ret >= 0 && ret <= 15);
85209 return ret;
85210}
85211
85212/* having this as a separate function provided a size benefit */
85213DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
85214 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
85215 return (duk_hex_dectab[x] >= 0);
85216 }
85217 return 0;
85218}
85219
85220/* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}. Shared by
85221 * source and RegExp parsing.
85222 */
85223DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) {
85224 duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */
85225 duk_codepoint_t escval;
85226 duk_codepoint_t x;
85227 duk_small_uint_t adv;
85228
85229 DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */
85230 DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U);
85231 DUK_UNREF(allow_es6);
85232
85233 adv = 2;
85234 digits = 2;
85235 if (DUK__L1() == DUK_ASC_LC_U) {
85236 digits = 4;
85237#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
85238 if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) {
85239 digits = 0;
85240 adv = 3;
85241 }
85242#endif
85243 }
85244 DUK__ADVANCECHARS(lex_ctx, adv);
85245
85246 escval = 0;
85247 for (;;) {
85248 /* One of the escape forms: \xHH, \uHHHH, \u{H+}.
85249 * The 'digits' variable tracks parsing state and is
85250 * initialized to:
85251 *
85252 * \xHH 2
85253 * \uHH 4
85254 * \u{H+} 0 first time, updated to -1 to indicate
85255 * at least one digit has been parsed
85256 *
85257 * Octal parsing is handled separately because it can be
85258 * done with fixed lookahead and also has validation
85259 * rules which depend on the escape length (which is
85260 * variable).
85261 *
85262 * We don't need a specific check for x < 0 (end of
85263 * input) or duk_unicode_is_line_terminator(x)
85264 * because the 'dig' decode will fail and lead to a
85265 * SyntaxError.
85266 */
85267 duk_codepoint_t dig;
85268
85269 x = DUK__L0();
85270 DUK__ADVANCECHARS(lex_ctx, 1);
85271
85272 dig = duk__hexval_validate(x);
85273 if (digits > 0) {
85274 digits--;
85275 if (dig < 0) {
85276 goto fail_escape;
85277 }
85278 DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
85279 escval = (escval << 4) + dig;
85280 if (digits == 0) {
85281 DUK_ASSERT(escval >= 0 && escval <= 0xffffL);
85282 break;
85283 }
85284 } else {
85285#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
85286 DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */);
85287 if (dig >= 0) {
85288 DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
85289 escval = (escval << 4) + dig;
85290 if (escval > 0x10ffffL) {
85291 goto fail_escape;
85292 }
85293 } else if (x == DUK_ASC_RCURLY) {
85294 if (digits == 0) {
85295 /* Empty escape, \u{}. */
85296 goto fail_escape;
85297 }
85298 DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL);
85299 break;
85300 } else {
85301 goto fail_escape;
85302 }
85303 digits = -1; /* Indicate we have at least one digit. */
85304#else /* DUK_USE_ES6_UNICODE_ESCAPE */
85305 DUK_ASSERT(0); /* Never happens if \u{H+} support disabled. */
85306#endif /* DUK_USE_ES6_UNICODE_ESCAPE */
85307 }
85308 }
85309
85310 return escval;
85311
85312 fail_escape:
85313 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
85314 DUK_WO_NORETURN(return 0;);
85315}
85316
85317/* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum
85318 * allowed value is \0377 (U+00FF), longest match is used. Used for both string
85319 * RegExp octal escape parsing. Window[0] must be the slash '\' and the first
85320 * digit must already be validated to be in [0-9] by the caller.
85321 */
85322DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_uint_t *out_adv, duk_bool_t reject_annex_b) {
85323 duk_codepoint_t cp;
85324 duk_small_uint_t lookup_idx;
85325 duk_small_uint_t adv;
85326 duk_codepoint_t tmp;
85327
85328 DUK_ASSERT(out_adv != NULL);
85329 DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH);
85330 DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9);
85331
85332 cp = 0;
85333 tmp = 0;
85334 for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) {
85335 DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
85336 tmp = DUK__LOOKUP(lex_ctx, lookup_idx);
85337 if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) {
85338 /* No more valid digits. */
85339 break;
85340 }
85341 tmp = (cp << 3) + (tmp - DUK_ASC_0);
85342 if (tmp > 0xff) {
85343 /* Three digit octal escapes above \377 (= 0xff)
85344 * are not allowed.
85345 */
85346 break;
85347 }
85348 cp = tmp;
85349 }
85350 DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
85351
85352 adv = lookup_idx;
85353 if (lookup_idx == 1) {
85354 DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too"));
85355 DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9);
85356 cp = tmp;
85357 adv++; /* correction to above, eat offending character */
85358 } else if (lookup_idx == 2 && cp == 0) {
85359 /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not.
85360 * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError.
85361 */
85362 DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too"));
85363 } else {
85364 /* This clause also handles non-shortest zero, e.g. \00. */
85365 if (reject_annex_b) {
85366 DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp));
85367 cp = -1;
85368 } else {
85369 DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp));
85370 DUK_ASSERT(cp >= 0 && cp <= 0xff);
85371 }
85372 }
85373
85374 *out_adv = adv;
85375
85376 DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b));
85377 return cp;
85378}
85379
85380/* XXX: move strict mode to lex_ctx? */
85381DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) {
85382 duk_small_uint_t adv;
85383
85384 for (adv = 1 /* initial quote */ ;;) {
85385 duk_codepoint_t x;
85386
85387 DUK__ADVANCECHARS(lex_ctx, adv); /* eat opening quote on first loop */
85388 x = DUK__L0();
85389
85390 adv = 1;
85391 if (x == quote) {
85392 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
85393 break;
85394 } else if (x == '\\') {
85395 /* DUK__L0 -> '\' char
85396 * DUK__L1 ... DUK__L5 -> more lookup
85397 */
85398 duk_small_int_t emitcp = -1;
85399
85400 x = DUK__L1();
85401
85402 /* How much to advance before next loop. */
85403 adv = 2; /* note: long live range */
85404
85405 switch (x) {
85406 case '\'':
85407 emitcp = 0x0027;
85408 break;
85409 case '"':
85410 emitcp = 0x0022;
85411 break;
85412 case '\\':
85413 emitcp = 0x005c;
85414 break;
85415 case 'b':
85416 emitcp = 0x0008;
85417 break;
85418 case 'f':
85419 emitcp = 0x000c;
85420 break;
85421 case 'n':
85422 emitcp = 0x000a;
85423 break;
85424 case 'r':
85425 emitcp = 0x000d;
85426 break;
85427 case 't':
85428 emitcp = 0x0009;
85429 break;
85430 case 'v':
85431 emitcp = 0x000b;
85432 break;
85433 case 'x':
85434 case 'u': {
85435 duk_codepoint_t esc_cp;
85436 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
85437 DUK__APPENDBUFFER(lex_ctx, esc_cp);
85438 adv = 0;
85439 break;
85440 }
85441 default: {
85442 if (duk_unicode_is_line_terminator(x)) {
85443 /* line continuation */
85444 if (x == 0x000d && DUK__L2() == 0x000a) {
85445 /* CR LF again a special case */
85446 adv = 3; /* line terminator, CR, LF */
85447 }
85448 } else if (DUK__ISDIGIT(x)) {
85449 /*
85450 * Octal escape or zero escape:
85451 * \0 (lookahead not OctalDigit)
85452 * \1 ... \7 (lookahead not OctalDigit)
85453 * \ZeroToThree OctalDigit (lookahead not OctalDigit)
85454 * \FourToSeven OctalDigit (no lookahead restrictions)
85455 * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
85456 *
85457 * Zero escape is part of the standard syntax. Octal escapes are
85458 * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
85459 * Any other productions starting with a decimal digit are invalid
85460 * but are in practice treated like identity escapes.
85461 *
85462 * Parse octal (up to 3 digits) from the lookup window.
85463 */
85464
85465 emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/);
85466 if (emitcp < 0) {
85467 goto fail_escape;
85468 }
85469 } else if (x < 0) {
85470 goto fail_unterminated;
85471 } else {
85472 /* escaped NonEscapeCharacter */
85473 DUK__APPENDBUFFER(lex_ctx, x);
85474 }
85475 } /* end default clause */
85476 } /* end switch */
85477
85478 /* Shared handling for single codepoint escapes. */
85479 if (emitcp >= 0) {
85480 DUK__APPENDBUFFER(lex_ctx, emitcp);
85481 }
85482
85483 /* Track number of escapes; count not really needed but directive
85484 * prologues need to detect whether there were any escapes or line
85485 * continuations or not.
85486 */
85487 out_token->num_escapes++;
85488 } else if (x >= 0x20 && x <= 0x7f) {
85489 /* Fast path for ASCII case, avoids line terminator
85490 * check and CESU-8 encoding.
85491 */
85492 DUK_ASSERT(x >= 0);
85493 DUK_ASSERT(!duk_unicode_is_line_terminator(x));
85494 DUK_ASSERT(x != quote);
85495 DUK_ASSERT(x != DUK_ASC_BACKSLASH);
85496 DUK__APPENDBUFFER_ASCII(lex_ctx, x);
85497 } else if (x < 0 || duk_unicode_is_line_terminator(x)) {
85498 goto fail_unterminated;
85499 } else {
85500 /* Character which is part of the string but wasn't handled
85501 * by the fast path.
85502 */
85503 DUK__APPENDBUFFER(lex_ctx, x);
85504 }
85505 } /* string parse loop */
85506
85507 return;
85508
85509 fail_escape:
85510 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
85511 DUK_WO_NORETURN(return;);
85512
85513 fail_unterminated:
85514 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING);
85515 DUK_WO_NORETURN(return;);
85516}
85517
85518/* Skip to end-of-line (or end-of-file), used for single line comments. */
85519DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) {
85520 for (;;) {
85521 duk_codepoint_t x;
85522
85523 x = DUK__L0();
85524 if (x < 0 || duk_unicode_is_line_terminator(x)) {
85525 break;
85526 }
85527 DUK__ADVANCECHARS(lex_ctx, 1);
85528 }
85529}
85530
85531/*
85532 * Parse ECMAScript source InputElementDiv or InputElementRegExp
85533 * (E5 Section 7), skipping whitespace, comments, and line terminators.
85534 *
85535 * Possible results are:
85536 * (1) a token
85537 * (2) a line terminator (skipped)
85538 * (3) a comment (skipped)
85539 * (4) EOF
85540 *
85541 * White space is automatically skipped from the current position (but
85542 * not after the input element). If input has already ended, returns
85543 * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR()
85544 * macro call (and hence a longjmp through current heap longjmp context).
85545 * Comments and line terminator tokens are automatically skipped.
85546 *
85547 * The input element being matched is determined by regexp_mode; if set,
85548 * parses a InputElementRegExp, otherwise a InputElementDiv. The
85549 * difference between these are handling of productions starting with a
85550 * forward slash.
85551 *
85552 * If strict_mode is set, recognizes additional future reserved words
85553 * specific to strict mode, and refuses to parse octal literals.
85554 *
85555 * The matching strategy below is to (currently) use a six character
85556 * lookup window to quickly determine which production is the -longest-
85557 * matching one, and then parse that. The top-level if-else clauses
85558 * match the first character, and the code blocks for each clause
85559 * handle -all- alternatives for that first character. ECMAScript
85560 * specification uses the "longest match wins" semantics, so the order
85561 * of the if-clauses matters.
85562 *
85563 * Misc notes:
85564 *
85565 * * ECMAScript numeric literals do not accept a sign character.
85566 * Consequently e.g. "-1.0" is parsed as two tokens: a negative
85567 * sign and a positive numeric literal. The compiler performs
85568 * the negation during compilation, so this has no adverse impact.
85569 *
85570 * * There is no token for "undefined": it is just a value available
85571 * from the global object (or simply established by doing a reference
85572 * to an undefined value).
85573 *
85574 * * Some contexts want Identifier tokens, which are IdentifierNames
85575 * excluding reserved words, while some contexts want IdentifierNames
85576 * directly. In the latter case e.g. "while" is interpreted as an
85577 * identifier name, not a DUK_TOK_WHILE token. The solution here is
85578 * to provide both token types: DUK_TOK_WHILE goes to 't' while
85579 * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
85580 * the identifier / keyword name.
85581 *
85582 * * Directive prologue needs to identify string literals such as
85583 * "use strict" and 'use strict', which are sensitive to line
85584 * continuations and escape sequences. For instance, "use\u0020strict"
85585 * is a valid directive but is distinct from "use strict". The solution
85586 * here is to decode escapes while tokenizing, but to keep track of the
85587 * number of escapes. Directive detection can then check that the
85588 * number of escapes is zero.
85589 *
85590 * * Multi-line comments with one or more internal LineTerminator are
85591 * treated like a line terminator to comply with automatic semicolon
85592 * insertion.
85593 */
85594
85595DUK_INTERNAL
85596void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
85597 duk_token *out_token,
85598 duk_bool_t strict_mode,
85599 duk_bool_t regexp_mode) {
85600 duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */
85601 duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
85602 * init is unnecessary but suppresses "may be used uninitialized" warnings.
85603 */
85604 duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
85605
85606 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
85607 goto fail_token_limit;
85608 }
85609
85610 out_token->t = DUK_TOK_EOF;
85611 out_token->t_nores = DUK_TOK_INVALID; /* marker: copy t if not changed */
85612#if 0 /* not necessary to init, disabled for faster parsing */
85613 out_token->num = DUK_DOUBLE_NAN;
85614 out_token->str1 = NULL;
85615 out_token->str2 = NULL;
85616#endif
85617 out_token->num_escapes = 0;
85618 /* out_token->lineterm set by caller */
85619
85620 /* This would be nice, but parsing is faster without resetting the
85621 * value slots. The only side effect is that references to temporary
85622 * string values may linger until lexing is finished; they're then
85623 * freed normally.
85624 */
85625#if 0
85626 duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx);
85627 duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx);
85628#endif
85629
85630 /* 'advtok' indicates how much to advance and which token id to assign
85631 * at the end. This shared functionality minimizes code size. All
85632 * code paths are required to set 'advtok' to some value, so no default
85633 * init value is used. Code paths calling DUK_ERROR() never return so
85634 * they don't need to set advtok.
85635 */
85636
85637 /*
85638 * Matching order:
85639 *
85640 * Punctuator first chars, also covers comments, regexps
85641 * LineTerminator
85642 * Identifier or reserved word, also covers null/true/false literals
85643 * NumericLiteral
85644 * StringLiteral
85645 * EOF
85646 *
85647 * The order does not matter as long as the longest match is
85648 * always correctly identified. There are order dependencies
85649 * in the clauses, so it's not trivial to convert to a switch.
85650 */
85651
85652 restart_lineupdate:
85653 out_token->start_line = lex_ctx->window[0].line;
85654
85655 restart:
85656 out_token->start_offset = lex_ctx->window[0].offset;
85657
85658 x = DUK__L0();
85659
85660 switch (x) {
85661 case DUK_ASC_SPACE:
85662 case DUK_ASC_HT: /* fast paths for space and tab */
85663 DUK__ADVANCECHARS(lex_ctx, 1);
85664 goto restart;
85665 case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
85666 DUK__ADVANCECHARS(lex_ctx, 1);
85667 got_lineterm = 1;
85668 goto restart_lineupdate;
85669#if defined(DUK_USE_SHEBANG_COMMENTS)
85670 case DUK_ASC_HASH: /* '#' */
85671 if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 &&
85672 (lex_ctx->flags & DUK_COMPILE_SHEBANG)) {
85673 /* "Shebang" comment ('#! ...') on first line. */
85674 /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
85675 duk__lexer_skip_to_endofline(lex_ctx);
85676 goto restart; /* line terminator will be handled on next round */
85677 }
85678 goto fail_token;
85679#endif /* DUK_USE_SHEBANG_COMMENTS */
85680 case DUK_ASC_SLASH: /* '/' */
85681 if (DUK__L1() == DUK_ASC_SLASH) {
85682 /*
85683 * E5 Section 7.4, allow SourceCharacter (which is any 16-bit
85684 * code point).
85685 */
85686
85687 /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
85688 duk__lexer_skip_to_endofline(lex_ctx);
85689 goto restart; /* line terminator will be handled on next round */
85690 } else if (DUK__L1() == DUK_ASC_STAR) {
85691 /*
85692 * E5 Section 7.4. If the multi-line comment contains a newline,
85693 * it is treated like a single line terminator for automatic
85694 * semicolon insertion.
85695 */
85696
85697 duk_bool_t last_asterisk = 0;
85698 DUK__ADVANCECHARS(lex_ctx, 2);
85699 for (;;) {
85700 x = DUK__L0();
85701 if (x < 0) {
85702 goto fail_unterm_comment;
85703 }
85704 DUK__ADVANCECHARS(lex_ctx, 1);
85705 if (last_asterisk && x == DUK_ASC_SLASH) {
85706 break;
85707 }
85708 if (duk_unicode_is_line_terminator(x)) {
85709 got_lineterm = 1;
85710 }
85711 last_asterisk = (x == DUK_ASC_STAR);
85712 }
85713 goto restart_lineupdate;
85714 } else if (regexp_mode) {
85715#if defined(DUK_USE_REGEXP_SUPPORT)
85716 /*
85717 * "/" followed by something in regexp mode. See E5 Section 7.8.5.
85718 *
85719 * RegExp parsing is a bit complex. First, the regexp body is delimited
85720 * by forward slashes, but the body may also contain forward slashes as
85721 * part of an escape sequence or inside a character class (delimited by
85722 * square brackets). A mini state machine is used to implement these.
85723 *
85724 * Further, an early (parse time) error must be thrown if the regexp
85725 * would cause a run-time error when used in the expression new RegExp(...).
85726 * Parsing here simply extracts the (candidate) regexp, and also accepts
85727 * invalid regular expressions (which are delimited properly). The caller
85728 * (compiler) must perform final validation and regexp compilation.
85729 *
85730 * RegExp first char may not be '/' (single line comment) or '*' (multi-
85731 * line comment). These have already been checked above, so there is no
85732 * need below for special handling of the first regexp character as in
85733 * the E5 productions.
85734 *
85735 * About unicode escapes within regexp literals:
85736 *
85737 * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
85738 * However, Section 6 states that regexps accept the escapes,
85739 * see paragraph starting with "In string literals...".
85740 * The regexp grammar, which sees the decoded regexp literal
85741 * (after lexical parsing) DOES have a \uHHHH unicode escape.
85742 * So, for instance:
85743 *
85744 * /\u1234/
85745 *
85746 * should first be parsed by the lexical grammar as:
85747 *
85748 * '\' 'u' RegularExpressionBackslashSequence
85749 * '1' RegularExpressionNonTerminator
85750 * '2' RegularExpressionNonTerminator
85751 * '3' RegularExpressionNonTerminator
85752 * '4' RegularExpressionNonTerminator
85753 *
85754 * and the escape itself is then parsed by the regexp engine.
85755 * This is the current implementation.
85756 *
85757 * Minor spec inconsistency:
85758 *
85759 * E5 Section 7.8.5 RegularExpressionBackslashSequence is:
85760 *
85761 * \ RegularExpressionNonTerminator
85762 *
85763 * while Section A.1 RegularExpressionBackslashSequence is:
85764 *
85765 * \ NonTerminator
85766 *
85767 * The latter is not normative and a typo.
85768 *
85769 */
85770
85771 /* first, parse regexp body roughly */
85772
85773 duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */
85774
85775 DUK__INITBUFFER(lex_ctx);
85776 for (;;) {
85777 DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
85778 x = DUK__L0();
85779 if (x < 0 || duk_unicode_is_line_terminator(x)) {
85780 goto fail_unterm_regexp;
85781 }
85782 x = DUK__L0(); /* re-read to avoid spill / fetch */
85783 if (state == 0) {
85784 if (x == DUK_ASC_SLASH) {
85785 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
85786 break;
85787 } else if (x == DUK_ASC_BACKSLASH) {
85788 state = 1;
85789 } else if (x == DUK_ASC_LBRACKET) {
85790 state = 2;
85791 }
85792 } else if (state == 1) {
85793 state = 0;
85794 } else if (state == 2) {
85795 if (x == DUK_ASC_RBRACKET) {
85796 state = 0;
85797 } else if (x == DUK_ASC_BACKSLASH) {
85798 state = 3;
85799 }
85800 } else { /* state == 3 */
85801 state = 2;
85802 }
85803 DUK__APPENDBUFFER(lex_ctx, x);
85804 }
85805 out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
85806
85807 /* second, parse flags */
85808
85809 DUK__INITBUFFER(lex_ctx);
85810 for (;;) {
85811 x = DUK__L0();
85812 if (!duk_unicode_is_identifier_part(x)) {
85813 break;
85814 }
85815 x = DUK__L0(); /* re-read to avoid spill / fetch */
85816 DUK__APPENDBUFFER(lex_ctx, x);
85817 DUK__ADVANCECHARS(lex_ctx, 1);
85818 }
85819 out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
85820
85821 DUK__INITBUFFER(lex_ctx); /* free some memory */
85822
85823 /* validation of the regexp is caller's responsibility */
85824
85825 advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
85826#else /* DUK_USE_REGEXP_SUPPORT */
85827 goto fail_regexp_support;
85828#endif /* DUK_USE_REGEXP_SUPPORT */
85829 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85830 /* "/=" and not in regexp mode */
85831 advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
85832 } else {
85833 /* "/" and not in regexp mode */
85834 advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
85835 }
85836 break;
85837 case DUK_ASC_LCURLY: /* '{' */
85838 advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
85839 break;
85840 case DUK_ASC_RCURLY: /* '}' */
85841 advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
85842 break;
85843 case DUK_ASC_LPAREN: /* '(' */
85844 advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
85845 break;
85846 case DUK_ASC_RPAREN: /* ')' */
85847 advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
85848 break;
85849 case DUK_ASC_LBRACKET: /* '[' */
85850 advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
85851 break;
85852 case DUK_ASC_RBRACKET: /* ']' */
85853 advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
85854 break;
85855 case DUK_ASC_PERIOD: /* '.' */
85856 if (DUK__ISDIGIT(DUK__L1())) {
85857 /* Period followed by a digit can only start DecimalLiteral
85858 * (handled in slow path). We could jump straight into the
85859 * DecimalLiteral handling but should avoid goto to inside
85860 * a block.
85861 */
85862 goto slow_path;
85863 }
85864 advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
85865 break;
85866 case DUK_ASC_SEMICOLON: /* ';' */
85867 advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
85868 break;
85869 case DUK_ASC_COMMA: /* ',' */
85870 advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
85871 break;
85872 case DUK_ASC_LANGLE: /* '<' */
85873#if defined(DUK_USE_HTML_COMMENTS)
85874 if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) {
85875 /*
85876 * ES2015: B.1.3, handle "<!--" SingleLineHTMLOpenComment
85877 */
85878
85879 /* DUK__ADVANCECHARS(lex_ctx, 4) would be correct here, but not necessary */
85880 duk__lexer_skip_to_endofline(lex_ctx);
85881 goto restart; /* line terminator will be handled on next round */
85882 }
85883 else
85884#endif /* DUK_USE_HTML_COMMENTS */
85885 if (DUK__L1() == DUK_ASC_LANGLE && DUK__L2() == DUK_ASC_EQUALS) {
85886 advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
85887 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85888 advtok = DUK__ADVTOK(2, DUK_TOK_LE);
85889 } else if (DUK__L1() == DUK_ASC_LANGLE) {
85890 advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
85891 } else {
85892 advtok = DUK__ADVTOK(1, DUK_TOK_LT);
85893 }
85894 break;
85895 case DUK_ASC_RANGLE: /* '>' */
85896 if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE && DUK__L3() == DUK_ASC_EQUALS) {
85897 advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
85898 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE) {
85899 advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
85900 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_EQUALS) {
85901 advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
85902 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85903 advtok = DUK__ADVTOK(2, DUK_TOK_GE);
85904 } else if (DUK__L1() == DUK_ASC_RANGLE) {
85905 advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
85906 } else {
85907 advtok = DUK__ADVTOK(1, DUK_TOK_GT);
85908 }
85909 break;
85910 case DUK_ASC_EQUALS: /* '=' */
85911 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
85912 advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
85913 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85914 advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
85915 } else {
85916 advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
85917 }
85918 break;
85919 case DUK_ASC_EXCLAMATION: /* '!' */
85920 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
85921 advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
85922 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85923 advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
85924 } else {
85925 advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
85926 }
85927 break;
85928 case DUK_ASC_PLUS: /* '+' */
85929 if (DUK__L1() == DUK_ASC_PLUS) {
85930 advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
85931 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85932 advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
85933 } else {
85934 advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
85935 }
85936 break;
85937 case DUK_ASC_MINUS: /* '-' */
85938#if defined(DUK_USE_HTML_COMMENTS)
85939 if (got_lineterm && DUK__L1() == DUK_ASC_MINUS && DUK__L2() == DUK_ASC_RANGLE) {
85940 /*
85941 * ES2015: B.1.3, handle "-->" SingleLineHTMLCloseComment
85942 * Only allowed:
85943 * - on new line
85944 * - preceded only by whitespace
85945 * - preceded by end of multiline comment and optional whitespace
85946 *
85947 * Since whitespace generates no tokens, and multiline comments
85948 * are treated as a line ending, consulting `got_lineterm` is
85949 * sufficient to test for these three options.
85950 */
85951
85952 /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */
85953 duk__lexer_skip_to_endofline(lex_ctx);
85954 goto restart; /* line terminator will be handled on next round */
85955 } else
85956#endif /* DUK_USE_HTML_COMMENTS */
85957 if (DUK__L1() == DUK_ASC_MINUS) {
85958 advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
85959 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85960 advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
85961 } else {
85962 advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
85963 }
85964 break;
85965 case DUK_ASC_STAR: /* '*' */
85966#if defined(DUK_USE_ES7_EXP_OPERATOR)
85967 if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) {
85968 advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ);
85969 } else if (DUK__L1() == DUK_ASC_STAR) {
85970 advtok = DUK__ADVTOK(2, DUK_TOK_EXP);
85971 } else
85972#endif
85973 if (DUK__L1() == DUK_ASC_EQUALS) {
85974 advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
85975 } else {
85976 advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
85977 }
85978 break;
85979 case DUK_ASC_PERCENT: /* '%' */
85980 if (DUK__L1() == DUK_ASC_EQUALS) {
85981 advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
85982 } else {
85983 advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
85984 }
85985 break;
85986 case DUK_ASC_AMP: /* '&' */
85987 if (DUK__L1() == DUK_ASC_AMP) {
85988 advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
85989 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85990 advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
85991 } else {
85992 advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
85993 }
85994 break;
85995 case DUK_ASC_PIPE: /* '|' */
85996 if (DUK__L1() == DUK_ASC_PIPE) {
85997 advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
85998 } else if (DUK__L1() == DUK_ASC_EQUALS) {
85999 advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
86000 } else {
86001 advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
86002 }
86003 break;
86004 case DUK_ASC_CARET: /* '^' */
86005 if (DUK__L1() == DUK_ASC_EQUALS) {
86006 advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
86007 } else {
86008 advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
86009 }
86010 break;
86011 case DUK_ASC_TILDE: /* '~' */
86012 advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
86013 break;
86014 case DUK_ASC_QUESTION: /* '?' */
86015 advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
86016 break;
86017 case DUK_ASC_COLON: /* ':' */
86018 advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
86019 break;
86020 case DUK_ASC_DOUBLEQUOTE: /* '"' */
86021 case DUK_ASC_SINGLEQUOTE: { /* '\'' */
86022 DUK__INITBUFFER(lex_ctx);
86023 duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode);
86024 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
86025 out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx);
86026
86027 DUK__INITBUFFER(lex_ctx); /* free some memory */
86028
86029 advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
86030 break;
86031 }
86032 default:
86033 goto slow_path;
86034 } /* switch */
86035
86036 goto skip_slow_path;
86037
86038 slow_path:
86039 if (duk_unicode_is_line_terminator(x)) {
86040 if (x == 0x000d && DUK__L1() == 0x000a) {
86041 /*
86042 * E5 Section 7.3: CR LF is detected as a single line terminator for
86043 * line numbers. Here we also detect it as a single line terminator
86044 * token.
86045 */
86046 DUK__ADVANCECHARS(lex_ctx, 2);
86047 } else {
86048 DUK__ADVANCECHARS(lex_ctx, 1);
86049 }
86050 got_lineterm = 1;
86051 goto restart_lineupdate;
86052 } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) {
86053 /*
86054 * Parse an identifier and then check whether it is:
86055 * - reserved word (keyword or other reserved word)
86056 * - "null" (NullLiteral)
86057 * - "true" (BooleanLiteral)
86058 * - "false" (BooleanLiteral)
86059 * - anything else => identifier
86060 *
86061 * This does not follow the E5 productions cleanly, but is
86062 * useful and compact.
86063 *
86064 * Note that identifiers may contain Unicode escapes,
86065 * see E5 Sections 6 and 7.6. They must be decoded first,
86066 * and the result checked against allowed characters.
86067 * The above if-clause accepts an identifier start and an
86068 * '\' character -- no other token can begin with a '\'.
86069 *
86070 * Note that "get" and "set" are not reserved words in E5
86071 * specification so they are recognized as plain identifiers
86072 * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
86073 * used now). The compiler needs to work around this.
86074 *
86075 * Strictly speaking, following ECMAScript longest match
86076 * specification, an invalid escape for the first character
86077 * should cause a syntax error. However, an invalid escape
86078 * for IdentifierParts should just terminate the identifier
86079 * early (longest match), and let the next tokenization
86080 * fail. For instance Rhino croaks with 'foo\z' when
86081 * parsing the identifier. This has little practical impact.
86082 */
86083
86084 duk_small_uint_t i, i_end;
86085 duk_bool_t first = 1;
86086 duk_hstring *str;
86087
86088 DUK__INITBUFFER(lex_ctx);
86089 for (;;) {
86090 /* re-lookup first char on first loop */
86091 if (DUK__L0() == DUK_ASC_BACKSLASH) {
86092 duk_codepoint_t esc_cp;
86093 if (DUK__L1() != DUK_ASC_LC_U) {
86094 goto fail_escape;
86095 }
86096 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
86097 DUK__APPENDBUFFER(lex_ctx, esc_cp);
86098
86099 /* IdentifierStart is stricter than IdentifierPart, so if the first
86100 * character is escaped, must have a stricter check here.
86101 */
86102 if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) {
86103 goto fail_escape;
86104 }
86105
86106 /* Track number of escapes: necessary for proper keyword
86107 * detection.
86108 */
86109 out_token->num_escapes++;
86110 } else {
86111 /* Note: first character is checked against this. But because
86112 * IdentifierPart includes all IdentifierStart characters, and
86113 * the first character (if unescaped) has already been checked
86114 * in the if condition, this is OK.
86115 */
86116 if (!duk_unicode_is_identifier_part(DUK__L0())) {
86117 break;
86118 }
86119 DUK__APPENDBUFFER(lex_ctx, DUK__L0());
86120 DUK__ADVANCECHARS(lex_ctx, 1);
86121 }
86122 first = 0;
86123 }
86124
86125 out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
86126 str = out_token->str1;
86127 out_token->t_nores = DUK_TOK_IDENTIFIER;
86128
86129 DUK__INITBUFFER(lex_ctx); /* free some memory */
86130
86131 /*
86132 * Interned identifier is compared against reserved words, which are
86133 * currently interned into the heap context. See genbuiltins.py.
86134 *
86135 * Note that an escape in the identifier disables recognition of
86136 * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
86137 * identifier named "if"). This is not necessarily compliant,
86138 * see test-dec-escaped-char-in-keyword.js.
86139 *
86140 * Note: "get" and "set" are awkward. They are not officially
86141 * ReservedWords (and indeed e.g. "var set = 1;" is valid), and
86142 * must come out as DUK_TOK_IDENTIFIER. The compiler needs to
86143 * work around this a bit.
86144 */
86145
86146 /* XXX: optimize by adding the token numbers directly into the
86147 * always interned duk_hstring objects (there should be enough
86148 * flag bits free for that)?
86149 */
86150
86151 i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
86152
86153 advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
86154 if (out_token->num_escapes == 0) {
86155 for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
86156 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
86157 DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS);
86158 if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
86159 advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
86160 break;
86161 }
86162 }
86163 }
86164 } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) {
86165 /* Note: decimal number may start with a period, but must be followed by a digit */
86166
86167 /*
86168 * Pre-parsing for decimal, hex, octal (both legacy and ES2015),
86169 * and binary literals, followed by an actual parser step
86170 * provided by numconv.
86171 *
86172 * Note: the leading sign character ('+' or '-') is -not- part of
86173 * the production in E5 grammar, and that the a DecimalLiteral
86174 * starting with a '0' must be followed by a non-digit.
86175 *
86176 * XXX: the two step parsing process is quite awkward, it would
86177 * be more straightforward to allow numconv to parse the longest
86178 * valid prefix (it already does that, it only needs to indicate
86179 * where the input ended). However, the lexer decodes characters
86180 * using a limited lookup window, so this is not a trivial change.
86181 */
86182
86183 /* XXX: because of the final check below (that the literal is not
86184 * followed by a digit), this could maybe be simplified, if we bail
86185 * out early from a leading zero (and if there are no periods etc).
86186 * Maybe too complex.
86187 */
86188
86189 duk_double_t val;
86190 duk_bool_t legacy_oct = 0;
86191 duk_small_int_t state; /* 0=before period/exp,
86192 * 1=after period, before exp
86193 * 2=after exp, allow '+' or '-'
86194 * 3=after exp and exp sign
86195 */
86196 duk_small_uint_t s2n_flags;
86197 duk_codepoint_t y, z;
86198 duk_small_int_t s2n_radix = 10;
86199 duk_small_uint_t pre_adv = 0;
86200
86201 DUK__INITBUFFER(lex_ctx);
86202 y = DUK__L1();
86203
86204 if (x == DUK_ASC_0) {
86205 z = DUK_LOWERCASE_CHAR_ASCII(y);
86206
86207 pre_adv = 2; /* default for 0xNNN, 0oNNN, 0bNNN. */
86208 if (z == DUK_ASC_LC_X) {
86209 s2n_radix = 16;
86210 } else if (z == DUK_ASC_LC_O) {
86211 s2n_radix = 8;
86212 } else if (z == DUK_ASC_LC_B) {
86213 s2n_radix = 2;
86214 } else {
86215 pre_adv = 0;
86216 if (DUK__ISDIGIT(y)) {
86217 if (strict_mode) {
86218 /* Reject octal like \07 but also octal-lookalike
86219 * decimal like \08 in strict mode.
86220 */
86221 goto fail_number_literal;
86222 } else {
86223 /* Legacy OctalIntegerLiteral or octal-lookalice
86224 * decimal. Deciding between the two happens below
86225 * in digit scanning.
86226 */
86227 DUK__APPENDBUFFER(lex_ctx, x);
86228 pre_adv = 1;
86229 legacy_oct = 1;
86230 s2n_radix = 8; /* tentative unless conflicting digits found */
86231 }
86232 }
86233 }
86234 }
86235
86236 DUK__ADVANCECHARS(lex_ctx, pre_adv);
86237
86238 /* XXX: we could parse integers here directly, and fall back
86239 * to numconv only when encountering a fractional expression
86240 * or when an octal literal turned out to be decimal (0778 etc).
86241 */
86242 state = 0;
86243 for (;;) {
86244 x = DUK__L0(); /* re-lookup curr char on first round */
86245 if (DUK__ISDIGIT(x)) {
86246 /* Note: intentionally allow leading zeroes here, as the
86247 * actual parser will check for them.
86248 */
86249 if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) {
86250 /* Started out as an octal-lookalike
86251 * but interpreted as decimal, e.g.
86252 * '0779' -> 779. This also means
86253 * that fractions are allowed, e.g.
86254 * '0779.123' is allowed but '0777.123'
86255 * is not!
86256 */
86257 s2n_radix = 10;
86258 }
86259 if (state == 2) {
86260 state = 3;
86261 }
86262 } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) {
86263 /* Note: 'e' and 'E' are also accepted here. */
86264 ;
86265 } else if (x == DUK_ASC_PERIOD) {
86266 if (state >= 1 || s2n_radix != 10) {
86267 break;
86268 } else {
86269 state = 1;
86270 }
86271 } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) {
86272 if (state >= 2 || s2n_radix != 10) {
86273 break;
86274 } else {
86275 state = 2;
86276 }
86277 } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) {
86278 if (state != 2) {
86279 break;
86280 } else {
86281 state = 3;
86282 }
86283 } else {
86284 break;
86285 }
86286 DUK__APPENDBUFFER(lex_ctx, x);
86287 DUK__ADVANCECHARS(lex_ctx, 1);
86288 }
86289
86290 /* XXX: better coercion */
86291 (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
86292
86293 if (s2n_radix != 10) {
86294 /* For bases other than 10, integer only. */
86295 s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
86296 } else {
86297 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
86298 DUK_S2N_FLAG_ALLOW_FRAC |
86299 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
86300 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
86301 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
86302 }
86303
86304 duk_dup(lex_ctx->thr, lex_ctx->slot1_idx);
86305 duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags);
86306 val = duk_to_number_m1(lex_ctx->thr);
86307 if (DUK_ISNAN(val)) {
86308 goto fail_number_literal;
86309 }
86310 duk_replace(lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
86311
86312 DUK__INITBUFFER(lex_ctx); /* free some memory */
86313
86314 /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
86315 * IdentifierStart or DecimalDigit.
86316 */
86317
86318 if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
86319 goto fail_number_literal;
86320 }
86321
86322 out_token->num = val;
86323 advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
86324 } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
86325 DUK__ADVANCECHARS(lex_ctx, 1);
86326 goto restart;
86327 } else if (x < 0) {
86328 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
86329 } else {
86330 goto fail_token;
86331 }
86332 skip_slow_path:
86333
86334 /*
86335 * Shared exit path
86336 */
86337
86338 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
86339 out_token->t = advtok & 0xff;
86340 if (out_token->t_nores == DUK_TOK_INVALID) {
86341 out_token->t_nores = out_token->t;
86342 }
86343 out_token->lineterm = got_lineterm;
86344
86345 /* Automatic semicolon insertion is allowed if a token is preceded
86346 * by line terminator(s), or terminates a statement list (right curly
86347 * or EOF).
86348 */
86349 if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
86350 out_token->allow_auto_semi = 1;
86351 } else {
86352 out_token->allow_auto_semi = 0;
86353 }
86354
86355 return;
86356
86357 fail_token_limit:
86358 DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
86359 DUK_WO_NORETURN(return;);
86360
86361 fail_token:
86362 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN);
86363 DUK_WO_NORETURN(return;);
86364
86365 fail_number_literal:
86366 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL);
86367 DUK_WO_NORETURN(return;);
86368
86369 fail_escape:
86370 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
86371 DUK_WO_NORETURN(return;);
86372
86373 fail_unterm_regexp:
86374 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP);
86375 DUK_WO_NORETURN(return;);
86376
86377 fail_unterm_comment:
86378 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT);
86379 DUK_WO_NORETURN(return;);
86380
86381#if !defined(DUK_USE_REGEXP_SUPPORT)
86382 fail_regexp_support:
86383 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED);
86384 DUK_WO_NORETURN(return;);
86385#endif
86386}
86387
86388#if defined(DUK_USE_REGEXP_SUPPORT)
86389
86390/*
86391 * Parse a RegExp token. The grammar is described in E5 Section 15.10.
86392 * Terminal constructions (such as quantifiers) are parsed directly here.
86393 *
86394 * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further,
86395 * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
86396 * will be accepted for a quantifier.
86397 */
86398
86399DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
86400 duk_small_uint_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
86401 duk_codepoint_t x, y;
86402
86403 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
86404 goto fail_token_limit;
86405 }
86406
86407 duk_memzero(out_token, sizeof(*out_token));
86408
86409 x = DUK__L0();
86410 y = DUK__L1();
86411
86412 DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
86413
86414 switch (x) {
86415 case DUK_ASC_PIPE: {
86416 advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
86417 break;
86418 }
86419 case DUK_ASC_CARET: {
86420 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
86421 break;
86422 }
86423 case DUK_ASC_DOLLAR: {
86424 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
86425 break;
86426 }
86427 case DUK_ASC_QUESTION: {
86428 out_token->qmin = 0;
86429 out_token->qmax = 1;
86430 if (y == DUK_ASC_QUESTION) {
86431 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
86432 out_token->greedy = 0;
86433 } else {
86434 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
86435 out_token->greedy = 1;
86436 }
86437 break;
86438 }
86439 case DUK_ASC_STAR: {
86440 out_token->qmin = 0;
86441 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
86442 if (y == DUK_ASC_QUESTION) {
86443 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
86444 out_token->greedy = 0;
86445 } else {
86446 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
86447 out_token->greedy = 1;
86448 }
86449 break;
86450 }
86451 case DUK_ASC_PLUS: {
86452 out_token->qmin = 1;
86453 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
86454 if (y == DUK_ASC_QUESTION) {
86455 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
86456 out_token->greedy = 0;
86457 } else {
86458 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
86459 out_token->greedy = 1;
86460 }
86461 break;
86462 }
86463 case DUK_ASC_LCURLY: {
86464 /* Production allows 'DecimalDigits', including leading zeroes */
86465 duk_uint32_t val1 = 0;
86466 duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
86467 duk_small_int_t digits = 0;
86468#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86469 duk_lexer_point lex_pt;
86470#endif
86471
86472#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86473 /* Store lexer position, restoring if quantifier is invalid. */
86474 DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
86475#endif
86476
86477 for (;;) {
86478 DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */
86479 x = DUK__L0();
86480 if (DUK__ISDIGIT(x)) {
86481 digits++;
86482 val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x);
86483 } else if (x == DUK_ASC_COMMA) {
86484 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
86485 goto invalid_quantifier;
86486 }
86487 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
86488 goto invalid_quantifier;
86489 }
86490 if (DUK__L1() == DUK_ASC_RCURLY) {
86491 /* form: { DecimalDigits , }, val1 = min count */
86492 if (digits == 0) {
86493 goto invalid_quantifier;
86494 }
86495 out_token->qmin = val1;
86496 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
86497 DUK__ADVANCECHARS(lex_ctx, 2);
86498 break;
86499 }
86500 val2 = val1;
86501 val1 = 0;
86502 digits = 0; /* not strictly necessary because of lookahead '}' above */
86503 } else if (x == DUK_ASC_RCURLY) {
86504 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
86505 goto invalid_quantifier;
86506 }
86507 if (digits == 0) {
86508 goto invalid_quantifier;
86509 }
86510 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
86511 /* val2 = min count, val1 = max count */
86512 out_token->qmin = val2;
86513 out_token->qmax = val1;
86514 } else {
86515 /* val1 = count */
86516 out_token->qmin = val1;
86517 out_token->qmax = val1;
86518 }
86519 DUK__ADVANCECHARS(lex_ctx, 1);
86520 break;
86521 } else {
86522 goto invalid_quantifier;
86523 }
86524 }
86525 if (DUK__L0() == DUK_ASC_QUESTION) {
86526 out_token->greedy = 0;
86527 DUK__ADVANCECHARS(lex_ctx, 1);
86528 } else {
86529 out_token->greedy = 1;
86530 }
86531 advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
86532 break;
86533 invalid_quantifier:
86534#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86535 /* Failed to match the quantifier, restore lexer and parse
86536 * opening brace as a literal.
86537 */
86538 DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
86539 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
86540 out_token->num = DUK_ASC_LCURLY;
86541#else
86542 goto fail_quantifier;
86543#endif
86544 break;
86545 }
86546 case DUK_ASC_PERIOD: {
86547 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
86548 break;
86549 }
86550 case DUK_ASC_BACKSLASH: {
86551 /* The E5.1 specification does not seem to allow IdentifierPart characters
86552 * to be used as identity escapes. Unfortunately this includes '$', which
86553 * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
86554 * Many other implementations (including V8 and Rhino, for instance) do
86555 * accept '\$' as a valid identity escape, which is quite pragmatic, and
86556 * ES2015 Annex B relaxes the rules to allow these (and other) real world forms.
86557 */
86558
86559 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
86560 if (y == DUK_ASC_LC_B) {
86561 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
86562 } else if (y == DUK_ASC_UC_B) {
86563 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
86564 } else if (y == DUK_ASC_LC_F) {
86565 out_token->num = 0x000c;
86566 } else if (y == DUK_ASC_LC_N) {
86567 out_token->num = 0x000a;
86568 } else if (y == DUK_ASC_LC_T) {
86569 out_token->num = 0x0009;
86570 } else if (y == DUK_ASC_LC_R) {
86571 out_token->num = 0x000d;
86572 } else if (y == DUK_ASC_LC_V) {
86573 out_token->num = 0x000b;
86574 } else if (y == DUK_ASC_LC_C) {
86575 x = DUK__L2();
86576 if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
86577 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
86578 out_token->num = (duk_uint32_t) (x % 32);
86579 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
86580 } else {
86581 goto fail_escape;
86582 }
86583 } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) {
86584 /* The token value is the Unicode codepoint without
86585 * it being decode into surrogate pair characters
86586 * here. The \u{H+} is only allowed in Unicode mode
86587 * which we don't support yet.
86588 */
86589 out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
86590 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR);
86591 } else if (y == DUK_ASC_LC_D) {
86592 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
86593 } else if (y == DUK_ASC_UC_D) {
86594 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
86595 } else if (y == DUK_ASC_LC_S) {
86596 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
86597 } else if (y == DUK_ASC_UC_S) {
86598 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
86599 } else if (y == DUK_ASC_LC_W) {
86600 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
86601 } else if (y == DUK_ASC_UC_W) {
86602 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
86603 } else if (DUK__ISDIGIT(y)) {
86604 /* E5 Section 15.10.2.11 */
86605 if (y == DUK_ASC_0) {
86606 if (DUK__ISDIGIT(DUK__L2())) {
86607 goto fail_escape;
86608 }
86609 out_token->num = 0x0000;
86610 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
86611 } else {
86612 /* XXX: shared parsing? */
86613 duk_uint32_t val = 0;
86614 duk_small_int_t i;
86615 for (i = 0; ; i++) {
86616 if (i >= DUK__MAX_RE_DECESC_DIGITS) {
86617 goto fail_escape;
86618 }
86619 DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
86620 x = DUK__L0();
86621 if (!DUK__ISDIGIT(x)) {
86622 break;
86623 }
86624 val = val * 10 + (duk_uint32_t) duk__hexval(x);
86625 }
86626 /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
86627 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
86628 out_token->num = val;
86629 }
86630#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86631 } else if (y >= 0) {
86632 /* For ES2015 Annex B, accept any source character as identity
86633 * escape except 'c' which is used for control characters.
86634 * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns
86635 * Careful not to match end-of-buffer (<0) here.
86636 * This is not yet full ES2015 Annex B because cases above
86637 * (like hex escape) won't backtrack.
86638 */
86639 DUK_ASSERT(y != DUK_ASC_LC_C); /* covered above */
86640#else /* DUK_USE_ES6_REGEXP_SYNTAX */
86641 } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
86642 y == DUK_UNICODE_CP_ZWNJ ||
86643 y == DUK_UNICODE_CP_ZWJ) {
86644 /* For ES5.1 identity escapes are not allowed for identifier
86645 * parts. This conflicts with a lot of real world code as this
86646 * doesn't e.g. allow escaping a dollar sign as /\$/, see
86647 * test-regexp-identity-escape-dollar.js.
86648 */
86649#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
86650 out_token->num = (duk_uint32_t) y;
86651 } else {
86652 goto fail_escape;
86653 }
86654 break;
86655 }
86656 case DUK_ASC_LPAREN: {
86657 /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
86658
86659 if (y == DUK_ASC_QUESTION) {
86660 if (DUK__L2() == DUK_ASC_EQUALS) {
86661 /* (?= */
86662 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
86663 } else if (DUK__L2() == DUK_ASC_EXCLAMATION) {
86664 /* (?! */
86665 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
86666 } else if (DUK__L2() == DUK_ASC_COLON) {
86667 /* (?: */
86668 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
86669 } else {
86670 goto fail_group;
86671 }
86672 } else {
86673 /* ( */
86674 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
86675 }
86676 break;
86677 }
86678 case DUK_ASC_RPAREN: {
86679 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
86680 break;
86681 }
86682 case DUK_ASC_LBRACKET: {
86683 /*
86684 * To avoid creating a heavy intermediate value for the list of ranges,
86685 * only the start token ('[' or '[^') is parsed here. The regexp
86686 * compiler parses the ranges itself.
86687 */
86688
86689 /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket
86690 * literal too, but it's not easy to parse without backtracking.
86691 */
86692
86693 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
86694 if (y == DUK_ASC_CARET) {
86695 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
86696 }
86697 break;
86698 }
86699#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
86700 case DUK_ASC_RCURLY:
86701 case DUK_ASC_RBRACKET: {
86702 /* Although these could be parsed as PatternCharacters unambiguously (here),
86703 * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
86704 */
86705 goto fail_invalid_char;
86706 break;
86707 }
86708#endif
86709 case -1: {
86710 /* EOF */
86711 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
86712 break;
86713 }
86714 default: {
86715 /* PatternCharacter, all excluded characters are matched by cases above */
86716 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
86717 out_token->num = (duk_uint32_t) x;
86718 break;
86719 }
86720 }
86721
86722 /*
86723 * Shared exit path
86724 */
86725
86726 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
86727 out_token->t = advtok & 0xff;
86728 return;
86729
86730 fail_token_limit:
86731 DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
86732 DUK_WO_NORETURN(return;);
86733
86734 fail_escape:
86735 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
86736 DUK_WO_NORETURN(return;);
86737
86738 fail_group:
86739 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP);
86740 DUK_WO_NORETURN(return;);
86741
86742#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
86743 fail_invalid_char:
86744 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER);
86745 DUK_WO_NORETURN(return;);
86746
86747 fail_quantifier:
86748 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER);
86749 DUK_WO_NORETURN(return;);
86750#endif
86751}
86752
86753/*
86754 * Special parser for character classes; calls callback for every
86755 * range parsed and returns the number of ranges present.
86756 */
86757
86758/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
86759 * required anyway. We could use that BUT we need to update the regexp compiler
86760 * 'nranges' too. Work this out a bit more cleanly to save space.
86761 */
86762
86763/* XXX: the handling of character range detection is a bit convoluted.
86764 * Try to simplify and make smaller.
86765 */
86766
86767/* XXX: logic for handling character ranges is now incorrect, it will accept
86768 * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though.
86769 *
86770 * Needs a read through and a lot of additional tests.
86771 */
86772
86773DUK_LOCAL
86774void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
86775 duk_re_range_callback gen_range,
86776 void *userdata,
86777 const duk_uint16_t *ranges,
86778 duk_small_int_t num) {
86779 const duk_uint16_t *ranges_end;
86780
86781 DUK_UNREF(lex_ctx);
86782
86783 ranges_end = ranges + num;
86784 while (ranges < ranges_end) {
86785 /* mark range 'direct', bypass canonicalization (see Wiki) */
86786 gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
86787 ranges += 2;
86788 }
86789}
86790
86791DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
86792 duk_codepoint_t start = -1;
86793 duk_codepoint_t ch;
86794 duk_codepoint_t x;
86795 duk_bool_t dash = 0;
86796 duk_small_uint_t adv = 0;
86797
86798 DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
86799
86800 for (;;) {
86801 DUK__ADVANCECHARS(lex_ctx, adv);
86802 adv = 1;
86803
86804 x = DUK__L0();
86805
86806 ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
86807 DUK_UNREF(ch);
86808
86809 if (x < 0) {
86810 goto fail_unterm_charclass;
86811 } else if (x == DUK_ASC_RBRACKET) {
86812 if (start >= 0) {
86813 gen_range(userdata, start, start, 0);
86814 }
86815 DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */
86816 break;
86817 } else if (x == DUK_ASC_MINUS) {
86818 if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) {
86819 /* '-' as a range indicator */
86820 dash = 1;
86821 continue;
86822 } else {
86823 /* '-' verbatim */
86824 ch = x;
86825 }
86826 } else if (x == DUK_ASC_BACKSLASH) {
86827 /*
86828 * The escapes are same as outside a character class, except that \b has a
86829 * different meaning, and \B and backreferences are prohibited (see E5
86830 * Section 15.10.2.19). However, it's difficult to share code because we
86831 * handle e.g. "\n" very differently: here we generate a single character
86832 * range for it.
86833 */
86834
86835 /* XXX: ES2015 surrogate pair handling. */
86836
86837 x = DUK__L1();
86838
86839 adv = 2;
86840
86841 if (x == DUK_ASC_LC_B) {
86842 /* Note: '\b' in char class is different than outside (assertion),
86843 * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
86844 * check below.
86845 */
86846 ch = 0x0008;
86847 } else if (x == DUK_ASC_LC_F) {
86848 ch = 0x000c;
86849 } else if (x == DUK_ASC_LC_N) {
86850 ch = 0x000a;
86851 } else if (x == DUK_ASC_LC_T) {
86852 ch = 0x0009;
86853 } else if (x == DUK_ASC_LC_R) {
86854 ch = 0x000d;
86855 } else if (x == DUK_ASC_LC_V) {
86856 ch = 0x000b;
86857 } else if (x == DUK_ASC_LC_C) {
86858 x = DUK__L2();
86859 adv = 3;
86860 if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
86861 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
86862 ch = (x % 32);
86863 } else {
86864 goto fail_escape;
86865 }
86866 } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) {
86867 /* The \u{H+} form is only allowed in Unicode mode which
86868 * we don't support yet.
86869 */
86870 ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
86871 adv = 0;
86872 } else if (x == DUK_ASC_LC_D) {
86873 duk__emit_u16_direct_ranges(lex_ctx,
86874 gen_range,
86875 userdata,
86876 duk_unicode_re_ranges_digit,
86877 sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
86878 ch = -1;
86879 } else if (x == DUK_ASC_UC_D) {
86880 duk__emit_u16_direct_ranges(lex_ctx,
86881 gen_range,
86882 userdata,
86883 duk_unicode_re_ranges_not_digit,
86884 sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
86885 ch = -1;
86886 } else if (x == DUK_ASC_LC_S) {
86887 duk__emit_u16_direct_ranges(lex_ctx,
86888 gen_range,
86889 userdata,
86890 duk_unicode_re_ranges_white,
86891 sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
86892 ch = -1;
86893 } else if (x == DUK_ASC_UC_S) {
86894 duk__emit_u16_direct_ranges(lex_ctx,
86895 gen_range,
86896 userdata,
86897 duk_unicode_re_ranges_not_white,
86898 sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
86899 ch = -1;
86900 } else if (x == DUK_ASC_LC_W) {
86901 duk__emit_u16_direct_ranges(lex_ctx,
86902 gen_range,
86903 userdata,
86904 duk_unicode_re_ranges_wordchar,
86905 sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
86906 ch = -1;
86907 } else if (x == DUK_ASC_UC_W) {
86908 duk__emit_u16_direct_ranges(lex_ctx,
86909 gen_range,
86910 userdata,
86911 duk_unicode_re_ranges_not_wordchar,
86912 sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
86913 ch = -1;
86914 } else if (DUK__ISDIGIT(x)) {
86915 /* DecimalEscape, only \0 is allowed, no leading
86916 * zeroes are allowed.
86917 *
86918 * ES2015 Annex B also allows (maximal match) legacy
86919 * octal escapes up to \377 and \8 and \9 are
86920 * accepted as literal '8' and '9', also in strict mode.
86921 */
86922
86923#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86924 ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/);
86925 DUK_ASSERT(ch >= 0); /* no rejections */
86926#else
86927 if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) {
86928 ch = 0x0000;
86929 } else {
86930 goto fail_escape;
86931 }
86932#endif
86933#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
86934 } else if (x >= 0) {
86935 /* IdentityEscape: ES2015 Annex B allows almost all
86936 * source characters here. Match anything except
86937 * EOF here.
86938 */
86939 ch = x;
86940#else /* DUK_USE_ES6_REGEXP_SYNTAX */
86941 } else if (!duk_unicode_is_identifier_part(x)) {
86942 /* IdentityEscape: ES5.1 doesn't allow identity escape
86943 * for identifier part characters, which conflicts with
86944 * some real world code. For example, it doesn't allow
86945 * /[\$]/ which is awkward.
86946 */
86947 ch = x;
86948#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
86949 } else {
86950 goto fail_escape;
86951 }
86952 } else {
86953 /* character represents itself */
86954 ch = x;
86955 }
86956
86957 /* ch is a literal character here or -1 if parsed entity was
86958 * an escape such as "\s".
86959 */
86960
86961 if (ch < 0) {
86962 /* multi-character sets not allowed as part of ranges, see
86963 * E5 Section 15.10.2.15, abstract operation CharacterRange.
86964 */
86965 if (start >= 0) {
86966 if (dash) {
86967 goto fail_range;
86968 } else {
86969 gen_range(userdata, start, start, 0);
86970 start = -1;
86971 /* dash is already 0 */
86972 }
86973 }
86974 } else {
86975 if (start >= 0) {
86976 if (dash) {
86977 if (start > ch) {
86978 goto fail_range;
86979 }
86980 gen_range(userdata, start, ch, 0);
86981 start = -1;
86982 dash = 0;
86983 } else {
86984 gen_range(userdata, start, start, 0);
86985 start = ch;
86986 /* dash is already 0 */
86987 }
86988 } else {
86989 start = ch;
86990 }
86991 }
86992 }
86993
86994 return;
86995
86996 fail_escape:
86997 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
86998 DUK_WO_NORETURN(return;);
86999
87000 fail_range:
87001 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE);
87002 DUK_WO_NORETURN(return;);
87003
87004 fail_unterm_charclass:
87005 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS);
87006 DUK_WO_NORETURN(return;);
87007}
87008
87009#endif /* DUK_USE_REGEXP_SUPPORT */
87010
87011/* automatic undefs */
87012#undef DUK__ADVANCEBYTES
87013#undef DUK__ADVANCECHARS
87014#undef DUK__ADVTOK
87015#undef DUK__APPENDBUFFER
87016#undef DUK__APPENDBUFFER_ASCII
87017#undef DUK__INITBUFFER
87018#undef DUK__ISDIGIT
87019#undef DUK__ISDIGIT03
87020#undef DUK__ISDIGIT47
87021#undef DUK__ISHEXDIGIT
87022#undef DUK__ISOCTDIGIT
87023#undef DUK__L0
87024#undef DUK__L1
87025#undef DUK__L2
87026#undef DUK__L3
87027#undef DUK__L4
87028#undef DUK__L5
87029#undef DUK__LOOKUP
87030#undef DUK__MAX_RE_DECESC_DIGITS
87031#undef DUK__MAX_RE_QUANT_DIGITS
87032#line 1 "duk_numconv.c"
87033/*
87034 * Number-to-string and string-to-number conversions.
87035 *
87036 * Slow path number-to-string and string-to-number conversion is based on
87037 * a Dragon4 variant, with fast paths for small integers. Big integer
87038 * arithmetic is needed for guaranteeing that the conversion is correct
87039 * and uses a minimum number of digits. The big number arithmetic has a
87040 * fixed maximum size and does not require dynamic allocations.
87041 *
87042 * See: doc/number-conversion.rst.
87043 */
87044
87045/* #include duk_internal.h -> already included */
87046
87047#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
87048#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
87049
87050#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
87051
87052/*
87053 * Tables generated with util/gennumdigits.py.
87054 *
87055 * duk__str2num_digits_for_radix indicates, for each radix, how many input
87056 * digits should be considered significant for string-to-number conversion.
87057 * The input is also padded to this many digits to give the Dragon4
87058 * conversion enough (apparent) precision to work with.
87059 *
87060 * duk__str2num_exp_limits indicates, for each radix, the radix-specific
87061 * minimum/maximum exponent values (for a Dragon4 integer mantissa)
87062 * below and above which the number is guaranteed to underflow to zero
87063 * or overflow to Infinity. This allows parsing to keep bigint values
87064 * bounded.
87065 */
87066
87067DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
87068 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */
87069 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */
87070 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */
87071 14, 14, 14, 14, 14 /* 31 to 36 */
87072};
87073
87074typedef struct {
87075 duk_int16_t upper;
87076 duk_int16_t lower;
87077} duk__exp_limits;
87078
87079DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
87080 { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 },
87081 { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 },
87082 { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 },
87083 { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 },
87084 { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 },
87085 { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 },
87086 { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 },
87087 { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 },
87088 { 190, -228 }, { 188, -226 }, { 187, -225 },
87089};
87090
87091/*
87092 * Limited functionality bigint implementation.
87093 *
87094 * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
87095 * with the caller responsible for ensuring this is never exceeded. No memory
87096 * allocation (except stack) is needed for bigint computation. Operations
87097 * have been tailored for number conversion needs.
87098 *
87099 * Argument order is "assignment order", i.e. target first, then arguments:
87100 * x <- y * z --> duk__bi_mul(x, y, z);
87101 */
87102
87103/* This upper value has been experimentally determined; debug build will check
87104 * bigint size with assertions.
87105 */
87106#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
87107
87108#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
87109#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
87110#else
87111#define DUK__BI_PRINT(name,x)
87112#endif
87113
87114/* Current size is about 152 bytes. */
87115typedef struct {
87116 duk_small_int_t n;
87117 duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
87118} duk__bigint;
87119
87120#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
87121DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
87122 /* Overestimate required size; debug code so not critical to be tight. */
87123 char buf[DUK__BI_MAX_PARTS * 9 + 64];
87124 char *p = buf;
87125 duk_small_int_t i;
87126
87127 /* No NUL term checks in this debug code. */
87128 p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
87129 if (x->n == 0) {
87130 p += DUK_SPRINTF(p, " 0");
87131 }
87132 for (i = x->n - 1; i >= 0; i--) {
87133 p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
87134 }
87135
87136 DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
87137}
87138#endif
87139
87140#if defined(DUK_USE_ASSERTIONS)
87141DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
87142 return (duk_small_int_t)
87143 ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
87144 ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
87145}
87146#endif
87147
87148DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
87149 duk_small_int_t i;
87150
87151 for (i = x->n - 1; i >= 0; i--) {
87152 if (x->v[i] != 0) {
87153 break;
87154 }
87155 }
87156
87157 /* Note: if 'x' is zero, x->n becomes 0 here */
87158 x->n = i + 1;
87159 DUK_ASSERT(duk__bi_is_valid(x));
87160}
87161
87162/* x <- y */
87163DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
87164 duk_small_int_t n;
87165
87166 n = y->n;
87167 x->n = n;
87168 /* No need to special case n == 0. */
87169 duk_memcpy((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n));
87170}
87171
87172DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
87173 if (v == 0U) {
87174 x->n = 0;
87175 } else {
87176 x->n = 1;
87177 x->v[0] = v;
87178 }
87179 DUK_ASSERT(duk__bi_is_valid(x));
87180}
87181
87182/* Return value: <0 <=> x < y
87183 * 0 <=> x == y
87184 * >0 <=> x > y
87185 */
87186DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
87187 duk_small_int_t i, nx, ny;
87188 duk_uint32_t tx, ty;
87189
87190 DUK_ASSERT(duk__bi_is_valid(x));
87191 DUK_ASSERT(duk__bi_is_valid(y));
87192
87193 nx = x->n;
87194 ny = y->n;
87195 if (nx > ny) {
87196 goto ret_gt;
87197 }
87198 if (nx < ny) {
87199 goto ret_lt;
87200 }
87201 for (i = nx - 1; i >= 0; i--) {
87202 tx = x->v[i];
87203 ty = y->v[i];
87204
87205 if (tx > ty) {
87206 goto ret_gt;
87207 }
87208 if (tx < ty) {
87209 goto ret_lt;
87210 }
87211 }
87212
87213 return 0;
87214
87215 ret_gt:
87216 return 1;
87217
87218 ret_lt:
87219 return -1;
87220}
87221
87222/* x <- y + z */
87223#if defined(DUK_USE_64BIT_OPS)
87224DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
87225 duk_uint64_t tmp;
87226 duk_small_int_t i, ny, nz;
87227
87228 DUK_ASSERT(duk__bi_is_valid(y));
87229 DUK_ASSERT(duk__bi_is_valid(z));
87230
87231 if (z->n > y->n) {
87232 duk__bigint *t;
87233 t = y; y = z; z = t;
87234 }
87235 DUK_ASSERT(y->n >= z->n);
87236
87237 ny = y->n; nz = z->n;
87238 tmp = 0U;
87239 for (i = 0; i < ny; i++) {
87240 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
87241 tmp += y->v[i];
87242 if (i < nz) {
87243 tmp += z->v[i];
87244 }
87245 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
87246 tmp = tmp >> 32;
87247 }
87248 if (tmp != 0U) {
87249 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
87250 x->v[i++] = (duk_uint32_t) tmp;
87251 }
87252 x->n = i;
87253 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
87254
87255 /* no need to normalize */
87256 DUK_ASSERT(duk__bi_is_valid(x));
87257}
87258#else /* DUK_USE_64BIT_OPS */
87259DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
87260 duk_uint32_t carry, tmp1, tmp2;
87261 duk_small_int_t i, ny, nz;
87262
87263 DUK_ASSERT(duk__bi_is_valid(y));
87264 DUK_ASSERT(duk__bi_is_valid(z));
87265
87266 if (z->n > y->n) {
87267 duk__bigint *t;
87268 t = y; y = z; z = t;
87269 }
87270 DUK_ASSERT(y->n >= z->n);
87271
87272 ny = y->n; nz = z->n;
87273 carry = 0U;
87274 for (i = 0; i < ny; i++) {
87275 /* Carry is detected based on wrapping which relies on exact 32-bit
87276 * types.
87277 */
87278 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
87279 tmp1 = y->v[i];
87280 tmp2 = tmp1;
87281 if (i < nz) {
87282 tmp2 += z->v[i];
87283 }
87284
87285 /* Careful with carry condition:
87286 * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
87287 * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
87288 */
87289 if (carry) {
87290 tmp2++;
87291 carry = (tmp2 <= tmp1 ? 1U : 0U);
87292 } else {
87293 carry = (tmp2 < tmp1 ? 1U : 0U);
87294 }
87295
87296 x->v[i] = tmp2;
87297 }
87298 if (carry) {
87299 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
87300 DUK_ASSERT(carry == 1U);
87301 x->v[i++] = carry;
87302 }
87303 x->n = i;
87304 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
87305
87306 /* no need to normalize */
87307 DUK_ASSERT(duk__bi_is_valid(x));
87308}
87309#endif /* DUK_USE_64BIT_OPS */
87310
87311/* x <- y + z */
87312DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
87313 duk__bigint tmp;
87314
87315 DUK_ASSERT(duk__bi_is_valid(y));
87316
87317 /* XXX: this could be optimized; there is only one call site now though */
87318 duk__bi_set_small(&tmp, z);
87319 duk__bi_add(x, y, &tmp);
87320
87321 DUK_ASSERT(duk__bi_is_valid(x));
87322}
87323
87324#if 0 /* unused */
87325/* x <- x + y, use t as temp */
87326DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
87327 duk__bi_add(t, x, y);
87328 duk__bi_copy(x, t);
87329}
87330#endif
87331
87332/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
87333#if defined(DUK_USE_64BIT_OPS)
87334DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
87335 duk_small_int_t i, ny, nz;
87336 duk_uint32_t ty, tz;
87337 duk_int64_t tmp;
87338
87339 DUK_ASSERT(duk__bi_is_valid(y));
87340 DUK_ASSERT(duk__bi_is_valid(z));
87341 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
87342 DUK_ASSERT(y->n >= z->n);
87343
87344 ny = y->n; nz = z->n;
87345 tmp = 0;
87346 for (i = 0; i < ny; i++) {
87347 ty = y->v[i];
87348 if (i < nz) {
87349 tz = z->v[i];
87350 } else {
87351 tz = 0;
87352 }
87353 tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
87354 x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL);
87355 tmp = tmp >> 32; /* 0 or -1 */
87356 }
87357 DUK_ASSERT(tmp == 0);
87358
87359 x->n = i;
87360 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
87361 DUK_ASSERT(duk__bi_is_valid(x));
87362}
87363#else
87364DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
87365 duk_small_int_t i, ny, nz;
87366 duk_uint32_t tmp1, tmp2, borrow;
87367
87368 DUK_ASSERT(duk__bi_is_valid(y));
87369 DUK_ASSERT(duk__bi_is_valid(z));
87370 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
87371 DUK_ASSERT(y->n >= z->n);
87372
87373 ny = y->n; nz = z->n;
87374 borrow = 0U;
87375 for (i = 0; i < ny; i++) {
87376 /* Borrow is detected based on wrapping which relies on exact 32-bit
87377 * types.
87378 */
87379 tmp1 = y->v[i];
87380 tmp2 = tmp1;
87381 if (i < nz) {
87382 tmp2 -= z->v[i];
87383 }
87384
87385 /* Careful with borrow condition:
87386 * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
87387 * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
87388 */
87389 if (borrow) {
87390 tmp2--;
87391 borrow = (tmp2 >= tmp1 ? 1U : 0U);
87392 } else {
87393 borrow = (tmp2 > tmp1 ? 1U : 0U);
87394 }
87395
87396 x->v[i] = tmp2;
87397 }
87398 DUK_ASSERT(borrow == 0U);
87399
87400 x->n = i;
87401 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
87402 DUK_ASSERT(duk__bi_is_valid(x));
87403}
87404#endif
87405
87406#if 0 /* unused */
87407/* x <- y - z */
87408DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
87409 duk__bigint tmp;
87410
87411 DUK_ASSERT(duk__bi_is_valid(y));
87412
87413 /* XXX: this could be optimized */
87414 duk__bi_set_small(&tmp, z);
87415 duk__bi_sub(x, y, &tmp);
87416
87417 DUK_ASSERT(duk__bi_is_valid(x));
87418}
87419#endif
87420
87421/* x <- x - y, use t as temp */
87422DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
87423 duk__bi_sub(t, x, y);
87424 duk__bi_copy(x, t);
87425}
87426
87427/* x <- y * z */
87428DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
87429 duk_small_int_t i, j, nx, nz;
87430
87431 DUK_ASSERT(duk__bi_is_valid(y));
87432 DUK_ASSERT(duk__bi_is_valid(z));
87433
87434 nx = y->n + z->n; /* max possible */
87435 DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
87436
87437 if (nx == 0) {
87438 /* Both inputs are zero; cases where only one is zero can go
87439 * through main algorithm.
87440 */
87441 x->n = 0;
87442 return;
87443 }
87444
87445 duk_memzero((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx));
87446 x->n = nx;
87447
87448 nz = z->n;
87449 for (i = 0; i < y->n; i++) {
87450#if defined(DUK_USE_64BIT_OPS)
87451 duk_uint64_t tmp = 0U;
87452 for (j = 0; j < nz; j++) {
87453 tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
87454 x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
87455 tmp = tmp >> 32;
87456 }
87457 if (tmp > 0) {
87458 DUK_ASSERT(i + j < nx);
87459 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
87460 DUK_ASSERT(x->v[i+j] == 0U);
87461 x->v[i+j] = (duk_uint32_t) tmp;
87462 }
87463#else
87464 /*
87465 * Multiply + add + carry for 32-bit components using only 16x16->32
87466 * multiplies and carry detection based on unsigned overflow.
87467 *
87468 * 1st mult, 32-bit: (A*2^16 + B)
87469 * 2nd mult, 32-bit: (C*2^16 + D)
87470 * 3rd add, 32-bit: E
87471 * 4th add, 32-bit: F
87472 *
87473 * (AC*2^16 + B) * (C*2^16 + D) + E + F
87474 * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
87475 * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
87476 * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
87477 */
87478 duk_uint32_t a, b, c, d, e, f;
87479 duk_uint32_t r, s, t;
87480
87481 a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
87482
87483 f = 0;
87484 for (j = 0; j < nz; j++) {
87485 c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
87486 e = x->v[i+j];
87487
87488 /* build result as: (r << 32) + s: start with (BD + E + F) */
87489 r = 0;
87490 s = b * d;
87491
87492 /* add E */
87493 t = s + e;
87494 if (t < s) { r++; } /* carry */
87495 s = t;
87496
87497 /* add F */
87498 t = s + f;
87499 if (t < s) { r++; } /* carry */
87500 s = t;
87501
87502 /* add BC*2^16 */
87503 t = b * c;
87504 r += (t >> 16);
87505 t = s + ((t & 0xffffUL) << 16);
87506 if (t < s) { r++; } /* carry */
87507 s = t;
87508
87509 /* add AD*2^16 */
87510 t = a * d;
87511 r += (t >> 16);
87512 t = s + ((t & 0xffffUL) << 16);
87513 if (t < s) { r++; } /* carry */
87514 s = t;
87515
87516 /* add AC*2^32 */
87517 t = a * c;
87518 r += t;
87519
87520 DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
87521 (unsigned long) y->v[i], (unsigned long) z->v[j],
87522 (unsigned long) x->v[i+j], (unsigned long) r,
87523 (unsigned long) s));
87524
87525 x->v[i+j] = s;
87526 f = r;
87527 }
87528 if (f > 0U) {
87529 DUK_ASSERT(i + j < nx);
87530 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
87531 DUK_ASSERT(x->v[i+j] == 0U);
87532 x->v[i+j] = (duk_uint32_t) f;
87533 }
87534#endif /* DUK_USE_64BIT_OPS */
87535 }
87536
87537 duk__bi_normalize(x);
87538 DUK_ASSERT(duk__bi_is_valid(x));
87539}
87540
87541/* x <- y * z */
87542DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
87543 duk__bigint tmp;
87544
87545 DUK_ASSERT(duk__bi_is_valid(y));
87546
87547 /* XXX: this could be optimized */
87548 duk__bi_set_small(&tmp, z);
87549 duk__bi_mul(x, y, &tmp);
87550
87551 DUK_ASSERT(duk__bi_is_valid(x));
87552}
87553
87554/* x <- x * y, use t as temp */
87555DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
87556 duk__bi_mul(t, x, y);
87557 duk__bi_copy(x, t);
87558}
87559
87560/* x <- x * y, use t as temp */
87561DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
87562 duk__bi_mul_small(t, x, y);
87563 duk__bi_copy(x, t);
87564}
87565
87566DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
87567 DUK_ASSERT(duk__bi_is_valid(x));
87568 return (x->n == 0) || ((x->v[0] & 0x01) == 0);
87569}
87570
87571DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
87572 DUK_ASSERT(duk__bi_is_valid(x));
87573 return (x->n == 0); /* this is the case for normalized numbers */
87574}
87575
87576/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values
87577 * which are at the lowest edge (next floating point value downwards has
87578 * a different exponent). The lowest mantissa has the form:
87579 *
87580 * 1000........000 (52 zeroes; only "hidden bit" is set)
87581 */
87582DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
87583 DUK_ASSERT(duk__bi_is_valid(x));
87584 return (duk_small_int_t)
87585 (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
87586}
87587
87588/* x <- (1<<y) */
87589DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
87590 duk_small_int_t n, r;
87591
87592 n = (y / 32) + 1;
87593 DUK_ASSERT(n > 0);
87594 r = y % 32;
87595 duk_memzero((void *) x->v, sizeof(duk_uint32_t) * (size_t) n);
87596 x->n = n;
87597 x->v[n - 1] = (((duk_uint32_t) 1) << r);
87598}
87599
87600/* x <- b^y; use t1 and t2 as temps */
87601DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_int_t y, duk__bigint *t1, duk__bigint *t2) {
87602 /* Fast path the binary case */
87603
87604 DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */
87605 DUK_ASSERT(b >= 0);
87606 DUK_ASSERT(y >= 0);
87607
87608 if (b == 2) {
87609 duk__bi_twoexp(x, y);
87610 return;
87611 }
87612
87613 /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
87614
87615 DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
87616
87617 duk__bi_set_small(x, 1);
87618 duk__bi_set_small(t1, (duk_uint32_t) b);
87619 for (;;) {
87620 /* Loop structure ensures that we don't compute t1^2 unnecessarily
87621 * on the final round, as that might create a bignum exceeding the
87622 * current DUK__BI_MAX_PARTS limit.
87623 */
87624 if (y & 0x01) {
87625 duk__bi_mul_copy(x, t1, t2);
87626 }
87627 y = y >> 1;
87628 if (y == 0) {
87629 break;
87630 }
87631 duk__bi_mul_copy(t1, t1, t2);
87632 }
87633
87634 DUK__BI_PRINT("exp_small result", x);
87635}
87636
87637/*
87638 * A Dragon4 number-to-string variant, based on:
87639 *
87640 * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
87641 * Accurately"
87642 *
87643 * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
87644 * Quickly and Accurately"
87645 *
87646 * The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
87647 * i.e. the base implementation without logarithm estimation speedups
87648 * (these would increase code footprint considerably). Fixed-format output
87649 * does not follow the suggestions in the paper; instead, we generate an
87650 * extra digit and round-with-carry.
87651 *
87652 * The same algorithm is used for number parsing (with b=10 and B=2)
87653 * by generating one extra digit and doing rounding manually.
87654 *
87655 * See doc/number-conversion.rst for limitations.
87656 */
87657
87658/* Maximum number of digits generated. */
87659#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */
87660
87661/* Maximum number of characters in formatted value. */
87662#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */
87663
87664/* Number and (minimum) size of bigints in the nc_ctx structure. */
87665#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
87666#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
87667
87668typedef struct {
87669 /* Currently about 7*152 = 1064 bytes. The space for these
87670 * duk__bigints is used also as a temporary buffer for generating
87671 * the final string. This is a bit awkard; a union would be
87672 * more correct.
87673 */
87674 duk__bigint f, r, s, mp, mm, t1, t2;
87675
87676 duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */
87677 duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */
87678 duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */
87679 duk_small_int_t abs_pos; /* digit position is absolute, not relative */
87680 duk_small_int_t e; /* exponent for 'f' */
87681 duk_small_int_t b; /* input radix */
87682 duk_small_int_t B; /* output radix */
87683 duk_small_int_t k; /* see algorithm */
87684 duk_small_int_t low_ok; /* see algorithm */
87685 duk_small_int_t high_ok; /* see algorithm */
87686 duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */
87687
87688 /* Buffer used for generated digits, values are in the range [0,B-1]. */
87689 duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
87690 duk_small_int_t count; /* digit count */
87691} duk__numconv_stringify_ctx;
87692
87693/* Note: computes with 'idx' in assertions, so caller beware.
87694 * 'idx' is preincremented, i.e. '1' on first call, because it
87695 * is more convenient for the caller.
87696 */
87697#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \
87698 DUK_ASSERT((preinc_idx) - 1 >= 0); \
87699 DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
87700 ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
87701 } while (0)
87702
87703DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
87704 duk_uint8_t *p;
87705 duk_size_t len;
87706 duk_small_int_t dig;
87707 duk_uint32_t t;
87708
87709 DUK_ASSERT(buf != NULL);
87710 DUK_ASSERT(radix >= 2 && radix <= 36);
87711
87712 /* A 32-bit unsigned integer formats to at most 32 digits (the
87713 * worst case happens with radix == 2). Output the digits backwards,
87714 * and use a memmove() to get them in the right place.
87715 */
87716
87717 p = buf + 32;
87718 for (;;) {
87719 t = x / (duk_uint32_t) radix;
87720 dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix);
87721 x = t;
87722
87723 DUK_ASSERT(dig >= 0 && dig < 36);
87724 *(--p) = DUK__DIGITCHAR(dig);
87725
87726 if (x == 0) {
87727 break;
87728 }
87729 }
87730 len = (duk_size_t) ((buf + 32) - p);
87731
87732 duk_memmove((void *) buf, (const void *) p, (size_t) len);
87733
87734 return len;
87735}
87736
87737DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
87738 duk_small_int_t lowest_mantissa;
87739
87740#if 1
87741 /* Assume IEEE round-to-even, so that shorter encoding can be used
87742 * when round-to-even would produce correct result. By removing
87743 * this check (and having low_ok == high_ok == 0) the results would
87744 * still be accurate but in some cases longer than necessary.
87745 */
87746 if (duk__bi_is_even(&nc_ctx->f)) {
87747 DUK_DDD(DUK_DDDPRINT("f is even"));
87748 nc_ctx->low_ok = 1;
87749 nc_ctx->high_ok = 1;
87750 } else {
87751 DUK_DDD(DUK_DDDPRINT("f is odd"));
87752 nc_ctx->low_ok = 0;
87753 nc_ctx->high_ok = 0;
87754 }
87755#else
87756 /* Note: not honoring round-to-even should work but now generates incorrect
87757 * results. For instance, 1e23 serializes to "a000...", i.e. the first digit
87758 * equals the radix (10). Scaling stops one step too early in this case.
87759 * Don't know why this is the case, but since this code path is unused, it
87760 * doesn't matter.
87761 */
87762 nc_ctx->low_ok = 0;
87763 nc_ctx->high_ok = 0;
87764#endif
87765
87766 /* For string-to-number, pretend we never have the lowest mantissa as there
87767 * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll
87768 * fall into the base cases for both e >= 0 and e < 0.
87769 */
87770 if (nc_ctx->is_s2n) {
87771 lowest_mantissa = 0;
87772 } else {
87773 lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
87774 }
87775
87776 nc_ctx->unequal_gaps = 0;
87777 if (nc_ctx->e >= 0) {
87778 /* exponent non-negative (and thus not minimum exponent) */
87779
87780 if (lowest_mantissa) {
87781 /* (>= e 0) AND (= f (expt b (- p 1)))
87782 *
87783 * be <- (expt b e) == b^e
87784 * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
87785 * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)]
87786 * s <- (* b 2) [if b==2 -> 4]
87787 * m+ <- be1 == b^(e+1)
87788 * m- <- be == b^e
87789 * k <- 0
87790 * B <- B
87791 * low_ok <- round
87792 * high_ok <- round
87793 */
87794
87795 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
87796 "lowest mantissa value for this exponent -> "
87797 "unequal gaps"));
87798
87799 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
87800 duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b); /* mp <- b^(e+1) */
87801 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
87802 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
87803 duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2)); /* s <- 2 * b */
87804 nc_ctx->unequal_gaps = 1;
87805 } else {
87806 /* (>= e 0) AND (not (= f (expt b (- p 1))))
87807 *
87808 * be <- (expt b e) == b^e
87809 * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)]
87810 * s <- 2
87811 * m+ <- be == b^e
87812 * m- <- be == b^e
87813 * k <- 0
87814 * B <- B
87815 * low_ok <- round
87816 * high_ok <- round
87817 */
87818
87819 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
87820 "not lowest mantissa for this exponent -> "
87821 "equal gaps"));
87822
87823 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
87824 duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */
87825 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
87826 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */
87827 duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */
87828 }
87829 } else {
87830 /* When doing string-to-number, lowest_mantissa is always 0 so
87831 * the exponent check, while incorrect, won't matter.
87832 */
87833 if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
87834 lowest_mantissa /* lowest mantissa for this exponent*/) {
87835 /* r <- (* f b 2) [if b==2 -> (* f 4)]
87836 * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)]
87837 * m+ <- b == 2
87838 * m- <- 1
87839 * k <- 0
87840 * B <- B
87841 * low_ok <- round
87842 * high_ok <- round
87843 */
87844
87845 DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
87846 "lowest mantissa for this exponent -> "
87847 "unequal gaps"));
87848
87849 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2)); /* r <- (2 * b) * f */
87850 duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, 1 - nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
87851 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
87852 duk__bi_set_small(&nc_ctx->mp, 2);
87853 duk__bi_set_small(&nc_ctx->mm, 1);
87854 nc_ctx->unequal_gaps = 1;
87855 } else {
87856 /* r <- (* f 2)
87857 * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)]
87858 * m+ <- 1
87859 * m- <- 1
87860 * k <- 0
87861 * B <- B
87862 * low_ok <- round
87863 * high_ok <- round
87864 */
87865
87866 DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
87867 "lowest mantissa for this exponent -> "
87868 "equal gaps"));
87869
87870 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */
87871 duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, -nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
87872 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */
87873 duk__bi_set_small(&nc_ctx->mp, 1);
87874 duk__bi_set_small(&nc_ctx->mm, 1);
87875 }
87876 }
87877}
87878
87879DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
87880 duk_small_int_t k = 0;
87881
87882 /* This is essentially the 'scale' algorithm, with recursion removed.
87883 * Note that 'k' is either correct immediately, or will move in one
87884 * direction in the loop. There's no need to do the low/high checks
87885 * on every round (like the Scheme algorithm does).
87886 *
87887 * The scheme algorithm finds 'k' and updates 's' simultaneously,
87888 * while the logical algorithm finds 'k' with 's' having its initial
87889 * value, after which 's' is updated separately (see the Burger-Dybvig
87890 * paper, Section 3.1, steps 2 and 3).
87891 *
87892 * The case where m+ == m- (almost always) is optimized for, because
87893 * it reduces the bigint operations considerably and almost always
87894 * applies. The scale loop only needs to work with m+, so this works.
87895 */
87896
87897 /* XXX: this algorithm could be optimized quite a lot by using e.g.
87898 * a logarithm based estimator for 'k' and performing B^n multiplication
87899 * using a lookup table or using some bit-representation based exp
87900 * algorithm. Currently we just loop, with significant performance
87901 * impact for very large and very small numbers.
87902 */
87903
87904 DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
87905 (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
87906 DUK__BI_PRINT("r(init)", &nc_ctx->r);
87907 DUK__BI_PRINT("s(init)", &nc_ctx->s);
87908 DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
87909 DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
87910
87911 for (;;) {
87912 DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
87913 DUK__BI_PRINT("r", &nc_ctx->r);
87914 DUK__BI_PRINT("s", &nc_ctx->s);
87915 DUK__BI_PRINT("m+", &nc_ctx->mp);
87916 DUK__BI_PRINT("m-", &nc_ctx->mm);
87917
87918 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
87919 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
87920 DUK_DDD(DUK_DDDPRINT("k is too low"));
87921 /* r <- r
87922 * s <- (* s B)
87923 * m+ <- m+
87924 * m- <- m-
87925 * k <- (+ k 1)
87926 */
87927
87928 duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
87929 k++;
87930 } else {
87931 break;
87932 }
87933 }
87934
87935 /* k > 0 -> k was too low, and cannot be too high */
87936 if (k > 0) {
87937 goto skip_dec_k;
87938 }
87939
87940 for (;;) {
87941 DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
87942 DUK__BI_PRINT("r", &nc_ctx->r);
87943 DUK__BI_PRINT("s", &nc_ctx->s);
87944 DUK__BI_PRINT("m+", &nc_ctx->mp);
87945 DUK__BI_PRINT("m-", &nc_ctx->mm);
87946
87947 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
87948 duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B); /* t2 = (* (+ r m+) B) */
87949 if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
87950 DUK_DDD(DUK_DDDPRINT("k is too high"));
87951 /* r <- (* r B)
87952 * s <- s
87953 * m+ <- (* m+ B)
87954 * m- <- (* m- B)
87955 * k <- (- k 1)
87956 */
87957 duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
87958 duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
87959 if (nc_ctx->unequal_gaps) {
87960 DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
87961 duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
87962 }
87963 k--;
87964 } else {
87965 break;
87966 }
87967 }
87968
87969 skip_dec_k:
87970
87971 if (!nc_ctx->unequal_gaps) {
87972 DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
87973 duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */
87974 }
87975 nc_ctx->k = k;
87976
87977 DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
87978 DUK__BI_PRINT("r(final)", &nc_ctx->r);
87979 DUK__BI_PRINT("s(final)", &nc_ctx->s);
87980 DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
87981 DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
87982}
87983
87984DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
87985 duk_small_int_t tc1, tc2; /* terminating conditions */
87986 duk_small_int_t d; /* current digit */
87987 duk_small_int_t count = 0; /* digit count */
87988
87989 /*
87990 * Digit generation loop.
87991 *
87992 * Different termination conditions:
87993 *
87994 * 1. Free format output. Terminate when shortest accurate
87995 * representation found.
87996 *
87997 * 2. Fixed format output, with specific number of digits.
87998 * Ignore termination conditions, terminate when digits
87999 * generated. Caller requests an extra digit and rounds.
88000 *
88001 * 3. Fixed format output, with a specific absolute cut-off
88002 * position (e.g. 10 digits after decimal point). Note
88003 * that we always generate at least one digit, even if
88004 * the digit is below the cut-off point already.
88005 */
88006
88007 for (;;) {
88008 DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
88009 (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
88010 (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
88011 DUK__BI_PRINT("r", &nc_ctx->r);
88012 DUK__BI_PRINT("s", &nc_ctx->s);
88013 DUK__BI_PRINT("m+", &nc_ctx->mp);
88014 DUK__BI_PRINT("m-", &nc_ctx->mm);
88015
88016 /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
88017 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B); /* t1 <- (* r B) */
88018 d = 0;
88019 for (;;) {
88020 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
88021 break;
88022 }
88023 duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */
88024 d++;
88025 }
88026 duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */
88027 /* d <- (quotient (* r B) s) (in range 0...B-1) */
88028 DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
88029 DUK__BI_PRINT("r(rem)", &nc_ctx->r);
88030
88031 duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
88032 duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
88033 DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
88034 DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
88035
88036 /* Terminating conditions. For fixed width output, we just ignore the
88037 * terminating conditions (and pretend that tc1 == tc2 == false). The
88038 * the current shortcut for fixed-format output is to generate a few
88039 * extra digits and use rounding (with carry) to finish the output.
88040 */
88041
88042 if (nc_ctx->is_fixed == 0) {
88043 /* free-form */
88044 tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
88045
88046 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */
88047 tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
88048
88049 DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
88050 } else {
88051 /* fixed-format */
88052 tc1 = 0;
88053 tc2 = 0;
88054 }
88055
88056 /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
88057 * on purpose, which is taken into account by the macro.
88058 */
88059 count++;
88060
88061 if (tc1) {
88062 if (tc2) {
88063 /* tc1 = true, tc2 = true */
88064 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
88065 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */
88066 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
88067 (long) d, (long) nc_ctx->k));
88068 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
88069 } else {
88070 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
88071 (long) (d + 1), (long) nc_ctx->k));
88072 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
88073 }
88074 break;
88075 } else {
88076 /* tc1 = true, tc2 = false */
88077 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
88078 (long) d, (long) nc_ctx->k));
88079 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
88080 break;
88081 }
88082 } else {
88083 if (tc2) {
88084 /* tc1 = false, tc2 = true */
88085 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
88086 (long) (d + 1), (long) nc_ctx->k));
88087 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
88088 break;
88089 } else {
88090 /* tc1 = false, tc2 = false */
88091 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
88092 (long) d, (long) nc_ctx->k));
88093 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
88094
88095 /* r <- r (updated above: r <- (remainder (* r B) s)
88096 * s <- s
88097 * m+ <- m+ (updated above: m+ <- (* m+ B)
88098 * m- <- m- (updated above: m- <- (* m- B)
88099 * B, low_ok, high_ok are fixed
88100 */
88101
88102 /* fall through and continue for-loop */
88103 }
88104 }
88105
88106 /* fixed-format termination conditions */
88107 if (nc_ctx->is_fixed) {
88108 if (nc_ctx->abs_pos) {
88109 int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */
88110 DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
88111 (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
88112 if (pos <= nc_ctx->req_digits) {
88113 DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
88114 break;
88115 }
88116 } else {
88117 DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
88118 (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
88119 if (count >= nc_ctx->req_digits) {
88120 DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
88121 break;
88122 }
88123 }
88124 }
88125 } /* for */
88126
88127 nc_ctx->count = count;
88128
88129 DUK_DDD(DUK_DDDPRINT("generate finished"));
88130
88131#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
88132 {
88133 duk_uint8_t buf[2048];
88134 duk_small_int_t i, t;
88135 duk_memzero(buf, sizeof(buf));
88136 for (i = 0; i < nc_ctx->count; i++) {
88137 t = nc_ctx->digits[i];
88138 if (t < 0 || t > 36) {
88139 buf[i] = (duk_uint8_t) '?';
88140 } else {
88141 buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
88142 }
88143 }
88144 DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
88145 (long) nc_ctx->k, (const char *) buf));
88146 }
88147#endif
88148}
88149
88150/* Round up digits to a given position. If position is out-of-bounds,
88151 * does nothing. If carry propagates over the first digit, a '1' is
88152 * prepended to digits and 'k' will be updated. Return value indicates
88153 * whether carry propagated over the first digit.
88154 *
88155 * Note that nc_ctx->count is NOT updated based on the rounding position
88156 * (it is updated only if carry overflows over the first digit and an
88157 * extra digit is prepended).
88158 */
88159DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
88160 duk_small_int_t t;
88161 duk_uint8_t *p;
88162 duk_uint8_t roundup_limit;
88163 duk_small_int_t ret = 0;
88164
88165 /*
88166 * round_idx points to the digit which is considered for rounding; the
88167 * digit to its left is the final digit of the rounded value. If round_idx
88168 * is zero, rounding will be performed; the result will either be an empty
88169 * rounded value or if carry happens a '1' digit is generated.
88170 */
88171
88172 if (round_idx >= nc_ctx->count) {
88173 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
88174 (long) round_idx, (long) nc_ctx->count));
88175 return 0;
88176 } else if (round_idx < 0) {
88177 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
88178 (long) round_idx));
88179 return 0;
88180 }
88181
88182 /*
88183 * Round-up limit.
88184 *
88185 * For even values, divides evenly, e.g. 10 -> roundup_limit=5.
88186 *
88187 * For odd values, rounds up, e.g. 3 -> roundup_limit=2.
88188 * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
88189 */
88190 roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
88191
88192 p = &nc_ctx->digits[round_idx];
88193 if (*p >= roundup_limit) {
88194 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
88195 /* carry */
88196 for (;;) {
88197 *p = 0;
88198 if (p == &nc_ctx->digits[0]) {
88199 DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
88200 duk_memmove((void *) (&nc_ctx->digits[1]),
88201 (const void *) (&nc_ctx->digits[0]),
88202 (size_t) (sizeof(char) * (size_t) nc_ctx->count));
88203 nc_ctx->digits[0] = 1; /* don't increase 'count' */
88204 nc_ctx->k++; /* position of highest digit changed */
88205 nc_ctx->count++; /* number of digits changed */
88206 ret = 1;
88207 break;
88208 }
88209
88210 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
88211 (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
88212 p--;
88213 t = *p;
88214 DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
88215 if (++t < nc_ctx->B) {
88216 DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
88217 *p = (duk_uint8_t) t;
88218 break;
88219 }
88220
88221 DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
88222 }
88223 }
88224
88225 return ret;
88226}
88227
88228#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
88229
88230DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
88231 duk_hthread *thr,
88232 duk_small_int_t radix,
88233 duk_small_int_t digits,
88234 duk_small_uint_t flags,
88235 duk_small_int_t neg) {
88236 duk_small_int_t k;
88237 duk_small_int_t pos, pos_end;
88238 duk_small_int_t expt;
88239 duk_small_int_t dig;
88240 duk_uint8_t *q;
88241 duk_uint8_t *buf;
88242
88243 /*
88244 * The string conversion here incorporates all the necessary ECMAScript
88245 * semantics without attempting to be generic. nc_ctx->digits contains
88246 * nc_ctx->count digits (>= 1), with the topmost digit's 'position'
88247 * indicated by nc_ctx->k as follows:
88248 *
88249 * digits="123" count=3 k=0 --> 0.123
88250 * digits="123" count=3 k=1 --> 1.23
88251 * digits="123" count=3 k=5 --> 12300
88252 * digits="123" count=3 k=-1 --> 0.0123
88253 *
88254 * Note that the identifier names used for format selection are different
88255 * in Burger-Dybvig paper and ECMAScript specification (quite confusingly
88256 * so, because e.g. 'k' has a totally different meaning in each). See
88257 * documentation for discussion.
88258 *
88259 * ECMAScript doesn't specify any specific behavior for format selection
88260 * (e.g. when to use exponent notation) for non-base-10 numbers.
88261 *
88262 * The bigint space in the context is reused for string output, as there
88263 * is more than enough space for that (>1kB at the moment), and we avoid
88264 * allocating even more stack.
88265 */
88266
88267 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
88268 DUK_ASSERT(nc_ctx->count >= 1);
88269
88270 k = nc_ctx->k;
88271 buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */
88272 q = buf;
88273
88274 /* Exponent handling: if exponent format is used, record exponent value and
88275 * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
88276 *
88277 * toFixed() prevents exponent use; otherwise apply a set of criteria to
88278 * match the other API calls (toString(), toPrecision, etc).
88279 */
88280
88281 expt = DUK__NO_EXP;
88282 if (!nc_ctx->abs_pos /* toFixed() */) {
88283 if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */
88284 ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */
88285 (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */
88286 ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */
88287 DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
88288 (long) k, (long) (k - 1)));
88289 expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
88290 k = 1; /* generate mantissa with a single leading whole number digit */
88291 }
88292 }
88293
88294 if (neg) {
88295 *q++ = '-';
88296 }
88297
88298 /* Start position (inclusive) and end position (exclusive) */
88299 pos = (k >= 1 ? k : 1);
88300 if (nc_ctx->is_fixed) {
88301 if (nc_ctx->abs_pos) {
88302 /* toFixed() */
88303 pos_end = -digits;
88304 } else {
88305 pos_end = k - digits;
88306 }
88307 } else {
88308 pos_end = k - nc_ctx->count;
88309 }
88310 if (pos_end > 0) {
88311 pos_end = 0;
88312 }
88313
88314 DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
88315 "digits=%ld, abs_pos=%ld",
88316 (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
88317 (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
88318
88319 /* Digit generation */
88320 while (pos > pos_end) {
88321 DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
88322 (long) pos, (long) pos_end));
88323 if (pos == 0) {
88324 *q++ = (duk_uint8_t) '.';
88325 }
88326 if (pos > k) {
88327 *q++ = (duk_uint8_t) '0';
88328 } else if (pos <= k - nc_ctx->count) {
88329 *q++ = (duk_uint8_t) '0';
88330 } else {
88331 dig = nc_ctx->digits[k - pos];
88332 DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
88333 *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
88334 }
88335
88336 pos--;
88337 }
88338 DUK_ASSERT(pos <= 1);
88339
88340 /* Exponent */
88341 if (expt != DUK__NO_EXP) {
88342 /*
88343 * Exponent notation for non-base-10 numbers isn't specified in ECMAScript
88344 * specification, as it never explicitly turns up: non-decimal numbers can
88345 * only be formatted with Number.prototype.toString([radix]) and for that,
88346 * behavior is not explicitly specified.
88347 *
88348 * Logical choices include formatting the exponent as decimal (e.g. binary
88349 * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
88350 * The Dragon4 algorithm (in the original paper) prints the exponent value
88351 * in the target radix B. However, for radix values 15 and above, the
88352 * exponent separator 'e' is no longer easily parseable. Consider, for
88353 * instance, the number "1.faecee+1c".
88354 */
88355
88356 duk_size_t len;
88357 char expt_sign;
88358
88359 *q++ = 'e';
88360 if (expt >= 0) {
88361 expt_sign = '+';
88362 } else {
88363 expt_sign = '-';
88364 expt = -expt;
88365 }
88366 *q++ = (duk_uint8_t) expt_sign;
88367 len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
88368 q += len;
88369 }
88370
88371 duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf));
88372}
88373
88374/*
88375 * Conversion helpers
88376 */
88377
88378DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
88379 duk_double_union u;
88380 duk_uint32_t tmp;
88381 duk_small_int_t expt;
88382
88383 /*
88384 * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
88385 * A B C D E F G H
88386 *
88387 * s sign bit
88388 * eee... exponent field
88389 * fff... fraction
88390 *
88391 * ieee value = 1.ffff... * 2^(e - 1023) (normal)
88392 * = 0.ffff... * 2^(-1022) (denormal)
88393 *
88394 * algorithm v = f * b^e
88395 */
88396
88397 DUK_DBLUNION_SET_DOUBLE(&u, x);
88398
88399 nc_ctx->f.n = 2;
88400
88401 tmp = DUK_DBLUNION_GET_LOW32(&u);
88402 nc_ctx->f.v[0] = tmp;
88403 tmp = DUK_DBLUNION_GET_HIGH32(&u);
88404 nc_ctx->f.v[1] = tmp & 0x000fffffUL;
88405 expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
88406
88407 if (expt == 0) {
88408 /* denormal */
88409 expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
88410 duk__bi_normalize(&nc_ctx->f);
88411 } else {
88412 /* normal: implicit leading 1-bit */
88413 nc_ctx->f.v[1] |= 0x00100000UL;
88414 expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
88415 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */
88416 }
88417
88418 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
88419
88420 nc_ctx->e = expt;
88421}
88422
88423DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
88424 duk_double_union u;
88425 duk_small_int_t expt;
88426 duk_small_int_t i;
88427 duk_small_int_t bitstart;
88428 duk_small_int_t bitround;
88429 duk_small_int_t bitidx;
88430 duk_small_int_t skip_round;
88431 duk_uint32_t t, v;
88432
88433 DUK_ASSERT(nc_ctx->count == 53 + 1);
88434
88435 /* Sometimes this assert is not true right now; it will be true after
88436 * rounding. See: test-bug-numconv-mantissa-assert.js.
88437 */
88438 DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */
88439
88440 /* Should not be required because the code below always sets both high
88441 * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
88442 * (perhaps because the low part is set (seemingly) conditionally in a
88443 * loop), so this is here to avoid the bogus warning.
88444 */
88445 duk_memzero((void *) &u, sizeof(u));
88446
88447 /*
88448 * Figure out how generated digits match up with the mantissa,
88449 * and then perform rounding. If mantissa overflows, need to
88450 * recompute the exponent (it is bumped and may overflow to
88451 * infinity).
88452 *
88453 * For normal numbers the leading '1' is hidden and ignored,
88454 * and the last bit is used for rounding:
88455 *
88456 * rounding pt
88457 * <--------52------->|
88458 * 1 x x x x ... x x x x|y ==> x x x x ... x x x x
88459 *
88460 * For denormals, the leading '1' is included in the number,
88461 * and the rounding point is different:
88462 *
88463 * rounding pt
88464 * <--52 or less--->|
88465 * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x
88466 *
88467 * The largest denormals will have a mantissa beginning with
88468 * a '1' (the explicit leading bit); smaller denormals will
88469 * have leading zero bits.
88470 *
88471 * If the exponent would become too high, the result becomes
88472 * Infinity. If the exponent is so small that the entire
88473 * mantissa becomes zero, the result becomes zero.
88474 *
88475 * Note: the Dragon4 'k' is off-by-one with respect to the IEEE
88476 * exponent. For instance, k==0 indicates that the leading '1'
88477 * digit is at the first binary fraction position (0.1xxx...);
88478 * the corresponding IEEE exponent would be -1.
88479 */
88480
88481 skip_round = 0;
88482
88483 recheck_exp:
88484
88485 expt = nc_ctx->k - 1; /* IEEE exp without bias */
88486 if (expt > 1023) {
88487 /* Infinity */
88488 bitstart = -255; /* needed for inf: causes mantissa to become zero,
88489 * and rounding to be skipped.
88490 */
88491 expt = 2047;
88492 } else if (expt >= -1022) {
88493 /* normal */
88494 bitstart = 1; /* skip leading digit */
88495 expt += DUK__IEEE_DOUBLE_EXP_BIAS;
88496 DUK_ASSERT(expt >= 1 && expt <= 2046);
88497 } else {
88498 /* denormal or zero */
88499 bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1);
88500 * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
88501 */
88502 expt = 0;
88503 }
88504 bitround = bitstart + 52;
88505
88506 DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
88507 (long) expt, (long) bitstart, (long) bitround));
88508
88509 if (!skip_round) {
88510 if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
88511 /* Corner case: see test-numconv-parse-mant-carry.js. We could
88512 * just bump the exponent and update bitstart, but it's more robust
88513 * to recompute (but avoid rounding twice).
88514 */
88515 DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
88516 skip_round = 1;
88517 goto recheck_exp;
88518 }
88519 }
88520
88521 /*
88522 * Create mantissa
88523 */
88524
88525 t = 0;
88526 for (i = 0; i < 52; i++) {
88527 bitidx = bitstart + 52 - 1 - i;
88528 if (bitidx >= nc_ctx->count) {
88529 v = 0;
88530 } else if (bitidx < 0) {
88531 v = 0;
88532 } else {
88533 v = nc_ctx->digits[bitidx];
88534 }
88535 DUK_ASSERT(v == 0 || v == 1);
88536 t += v << (i % 32);
88537 if (i == 31) {
88538 /* low 32 bits is complete */
88539 DUK_DBLUNION_SET_LOW32(&u, t);
88540 t = 0;
88541 }
88542 }
88543 /* t has high mantissa */
88544
88545 DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
88546 (unsigned long) t,
88547 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
88548
88549 DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
88550 t += ((duk_uint32_t) expt) << 20;
88551#if 0 /* caller handles sign change */
88552 if (negative) {
88553 t |= 0x80000000U;
88554 }
88555#endif
88556 DUK_DBLUNION_SET_HIGH32(&u, t);
88557
88558 DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
88559 (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
88560 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
88561
88562 *x = DUK_DBLUNION_GET_DOUBLE(&u);
88563}
88564
88565/*
88566 * Exposed number-to-string API
88567 *
88568 * Input: [ number ]
88569 * Output: [ string ]
88570 */
88571
88572DUK_LOCAL DUK_NOINLINE void duk__numconv_stringify_raw(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
88573 duk_double_t x;
88574 duk_small_int_t c;
88575 duk_small_int_t neg;
88576 duk_uint32_t uval;
88577 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
88578 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
88579
88580 x = (duk_double_t) duk_require_number(thr, -1);
88581 duk_pop(thr);
88582
88583 /*
88584 * Handle special cases (NaN, infinity, zero).
88585 */
88586
88587 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
88588 if (DUK_SIGNBIT((double) x)) {
88589 x = -x;
88590 neg = 1;
88591 } else {
88592 neg = 0;
88593 }
88594
88595 /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
88596 DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
88597
88598 if (c == DUK_FP_NAN) {
88599 duk_push_hstring_stridx(thr, DUK_STRIDX_NAN);
88600 return;
88601 } else if (c == DUK_FP_INFINITE) {
88602 if (neg) {
88603 /* -Infinity */
88604 duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY);
88605 } else {
88606 /* Infinity */
88607 duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY);
88608 }
88609 return;
88610 } else if (c == DUK_FP_ZERO) {
88611 /* We can't shortcut zero here if it goes through special formatting
88612 * (such as forced exponential notation).
88613 */
88614 ;
88615 }
88616
88617 /*
88618 * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
88619 * specially, as they're very likely for embedded programs. This
88620 * is now done for all radix values. We must be careful not to use
88621 * the fast path when special formatting (e.g. forced exponential)
88622 * is in force.
88623 *
88624 * XXX: could save space by supporting radix 10 only and using
88625 * sprintf "%lu" for the fast path and for exponent formatting.
88626 */
88627
88628 uval = duk_double_to_uint32_t(x);
88629 if (duk_double_equals((double) uval, x) && /* integer number in range */
88630 flags == 0) { /* no special formatting */
88631 /* use bigint area as a temp */
88632 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
88633 duk_uint8_t *p = buf;
88634
88635 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
88636 if (neg && uval != 0) {
88637 /* no negative sign for zero */
88638 *p++ = (duk_uint8_t) '-';
88639 }
88640 p += duk__dragon4_format_uint32(p, uval, radix);
88641 duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
88642 return;
88643 }
88644
88645 /*
88646 * Dragon4 setup.
88647 *
88648 * Convert double from IEEE representation for conversion;
88649 * normal finite values have an implicit leading 1-bit. The
88650 * slow path algorithm doesn't handle zero, so zero is special
88651 * cased here but still creates a valid nc_ctx, and goes
88652 * through normal formatting in case special formatting has
88653 * been requested (e.g. forced exponential format: 0 -> "0e+0").
88654 */
88655
88656 /* Would be nice to bulk clear the allocation, but the context
88657 * is 1-2 kilobytes and nothing should rely on it being zeroed.
88658 */
88659#if 0
88660 duk_memzero((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
88661#endif
88662
88663 nc_ctx->is_s2n = 0;
88664 nc_ctx->b = 2;
88665 nc_ctx->B = radix;
88666 nc_ctx->abs_pos = 0;
88667 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
88668 nc_ctx->is_fixed = 1;
88669 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
88670 /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
88671 * but add an extra digit for rounding.
88672 */
88673 nc_ctx->abs_pos = 1;
88674 nc_ctx->req_digits = (-digits + 1) - 1;
88675 } else {
88676 nc_ctx->req_digits = digits + 1;
88677 }
88678 } else {
88679 nc_ctx->is_fixed = 0;
88680 nc_ctx->req_digits = 0;
88681 }
88682
88683 if (c == DUK_FP_ZERO) {
88684 /* Zero special case: fake requested number of zero digits; ensure
88685 * no sign bit is printed. Relative and absolute fixed format
88686 * require separate handling.
88687 */
88688 duk_small_int_t count;
88689 if (nc_ctx->is_fixed) {
88690 if (nc_ctx->abs_pos) {
88691 count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
88692 } else {
88693 count = digits + 1; /* + 1 for rounding */
88694 }
88695 } else {
88696 count = 1;
88697 }
88698 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
88699 DUK_ASSERT(count >= 1);
88700 duk_memzero((void *) nc_ctx->digits, (size_t) count);
88701 nc_ctx->count = count;
88702 nc_ctx->k = 1; /* 0.000... */
88703 neg = 0;
88704 goto zero_skip;
88705 }
88706
88707 duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
88708 DUK__BI_PRINT("f", &nc_ctx->f);
88709 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
88710
88711 /*
88712 * Dragon4 slow path digit generation.
88713 */
88714
88715 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
88716
88717 DUK_DDD(DUK_DDDPRINT("after prepare:"));
88718 DUK__BI_PRINT("r", &nc_ctx->r);
88719 DUK__BI_PRINT("s", &nc_ctx->s);
88720 DUK__BI_PRINT("mp", &nc_ctx->mp);
88721 DUK__BI_PRINT("mm", &nc_ctx->mm);
88722
88723 duk__dragon4_scale(nc_ctx);
88724
88725 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
88726 DUK__BI_PRINT("r", &nc_ctx->r);
88727 DUK__BI_PRINT("s", &nc_ctx->s);
88728 DUK__BI_PRINT("mp", &nc_ctx->mp);
88729 DUK__BI_PRINT("mm", &nc_ctx->mm);
88730
88731 duk__dragon4_generate(nc_ctx);
88732
88733 /*
88734 * Convert and push final string.
88735 */
88736
88737 zero_skip:
88738
88739 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
88740 /* Perform fixed-format rounding. */
88741 duk_small_int_t roundpos;
88742 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
88743 /* 'roundpos' is relative to nc_ctx->k and increases to the right
88744 * (opposite of how 'k' changes).
88745 */
88746 roundpos = -digits; /* absolute position for digit considered for rounding */
88747 roundpos = nc_ctx->k - roundpos;
88748 } else {
88749 roundpos = digits;
88750 }
88751 DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
88752 (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
88753 (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
88754
88755 /* Note: 'count' is currently not adjusted by rounding (i.e. the
88756 * digits are not "chopped off". That shouldn't matter because
88757 * the digit position (absolute or relative) is passed on to the
88758 * convert-and-push function.
88759 */
88760 }
88761
88762 duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg);
88763}
88764
88765DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
88766 duk_native_stack_check(thr);
88767 duk__numconv_stringify_raw(thr, radix, digits, flags);
88768}
88769
88770/*
88771 * Exposed string-to-number API
88772 *
88773 * Input: [ string ]
88774 * Output: [ number ]
88775 *
88776 * If number parsing fails, a NaN is pushed as the result. If number parsing
88777 * fails due to an internal error, an InternalError is thrown.
88778 */
88779
88780DUK_LOCAL DUK_NOINLINE void duk__numconv_parse_raw(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) {
88781 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
88782 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
88783 duk_double_t res;
88784 duk_hstring *h_str;
88785 duk_int_t expt;
88786 duk_bool_t expt_neg;
88787 duk_small_int_t expt_adj;
88788 duk_small_int_t neg;
88789 duk_small_int_t dig;
88790 duk_small_int_t dig_whole;
88791 duk_small_int_t dig_lzero;
88792 duk_small_int_t dig_frac;
88793 duk_small_int_t dig_expt;
88794 duk_small_int_t dig_prec;
88795 const duk__exp_limits *explim;
88796 const duk_uint8_t *p;
88797 duk_small_int_t ch;
88798
88799 DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
88800 (duk_tval *) duk_get_tval(thr, -1),
88801 (long) radix, (unsigned long) flags));
88802
88803 DUK_ASSERT(radix >= 2 && radix <= 36);
88804 DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
88805
88806 /*
88807 * Preliminaries: trim, sign, Infinity check
88808 *
88809 * We rely on the interned string having a NUL terminator, which will
88810 * cause a parse failure wherever it is encountered. As a result, we
88811 * don't need separate pointer checks.
88812 *
88813 * There is no special parsing for 'NaN' in the specification although
88814 * 'Infinity' (with an optional sign) is allowed in some contexts.
88815 * Some contexts allow plus/minus sign, while others only allow the
88816 * minus sign (like JSON.parse()).
88817 *
88818 * Automatic hex number detection (leading '0x' or '0X') and octal
88819 * number detection (leading '0' followed by at least one octal digit)
88820 * is done here too.
88821 *
88822 * Symbols are not explicitly rejected here (that's up to the caller).
88823 * If a symbol were passed here, it should ultimately safely fail
88824 * parsing due to a syntax error.
88825 */
88826
88827 if (flags & DUK_S2N_FLAG_TRIM_WHITE) {
88828 /* Leading / trailing whitespace is sometimes accepted and
88829 * sometimes not. After white space trimming, all valid input
88830 * characters are pure ASCII.
88831 */
88832 duk_trim(thr, -1);
88833 }
88834 h_str = duk_require_hstring(thr, -1);
88835 DUK_ASSERT(h_str != NULL);
88836 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
88837
88838 neg = 0;
88839 ch = *p;
88840 if (ch == (duk_small_int_t) '+') {
88841 if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) {
88842 DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
88843 goto parse_fail;
88844 }
88845 p++;
88846 } else if (ch == (duk_small_int_t) '-') {
88847 if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) {
88848 DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
88849 goto parse_fail;
88850 }
88851 p++;
88852 neg = 1;
88853 }
88854
88855 if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity", 8) == 0) {
88856 /* Don't check for Infinity unless the context allows it.
88857 * 'Infinity' is a valid integer literal in e.g. base-36:
88858 *
88859 * parseInt('Infinity', 36)
88860 * 1461559270678
88861 */
88862
88863 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) {
88864 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
88865 goto parse_fail;
88866 } else {
88867 res = DUK_DOUBLE_INFINITY;
88868 goto negcheck_and_ret;
88869 }
88870 }
88871 ch = *p;
88872 if (ch == (duk_small_int_t) '0') {
88873 duk_small_int_t detect_radix = 0;
88874 ch = DUK_LOWERCASE_CHAR_ASCII(p[1]); /* 'x' or 'X' -> 'x' */
88875 if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) {
88876 DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
88877 detect_radix = 16;
88878#if 0
88879 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) &&
88880 (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
88881 DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
88882 detect_radix = 8;
88883
88884 /* NOTE: if this legacy octal case is added back, it has
88885 * different flags and 'p' advance so this needs to be
88886 * reworked.
88887 */
88888 flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO; /* interpret e.g. '09' as '0', not NaN */
88889 p += 1;
88890#endif
88891 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) {
88892 DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent"));
88893 detect_radix = 8;
88894 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) {
88895 DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent"));
88896 detect_radix = 2;
88897 }
88898 if (detect_radix > 0) {
88899 radix = detect_radix;
88900 /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
88901 flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
88902 DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
88903 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
88904 flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO; /* allow e.g. '0x0009' and '0b00010001' */
88905 p += 2;
88906 }
88907 }
88908
88909 /*
88910 * Scan number and setup for Dragon4.
88911 *
88912 * The fast path case is detected during setup: an integer which
88913 * can be converted without rounding, no net exponent. The fast
88914 * path could be implemented as a separate scan, but may not really
88915 * be worth it: the multiplications for building 'f' are not
88916 * expensive when 'f' is small.
88917 *
88918 * The significand ('f') must contain enough bits of (apparent)
88919 * accuracy, so that Dragon4 will generate enough binary output digits.
88920 * For decimal numbers, this means generating a 20-digit significand,
88921 * which should yield enough practical accuracy to parse IEEE doubles.
88922 * In fact, the ECMAScript specification explicitly allows an
88923 * implementation to treat digits beyond 20 as zeroes (and even
88924 * to round the 20th digit upwards). For non-decimal numbers, the
88925 * appropriate number of digits has been precomputed for comparable
88926 * accuracy.
88927 *
88928 * Digit counts:
88929 *
88930 * [ dig_lzero ]
88931 * |
88932 * .+-..---[ dig_prec ]----.
88933 * | || |
88934 * 0000123.456789012345678901234567890e+123456
88935 * | | | | | |
88936 * `--+--' `------[ dig_frac ]-------' `-+--'
88937 * | |
88938 * [ dig_whole ] [ dig_expt ]
88939 *
88940 * dig_frac and dig_expt are -1 if not present
88941 * dig_lzero is only computed for whole number part
88942 *
88943 * Parsing state
88944 *
88945 * Parsing whole part dig_frac < 0 AND dig_expt < 0
88946 * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
88947 * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
88948 *
88949 * Note: in case we hit an implementation limit (like exponent range),
88950 * we should throw an error, NOT return NaN or Infinity. Even with
88951 * very large exponent (or significand) values the final result may be
88952 * finite, so NaN/Infinity would be incorrect.
88953 */
88954
88955 duk__bi_set_small(&nc_ctx->f, 0);
88956 dig_prec = 0;
88957 dig_lzero = 0;
88958 dig_whole = 0;
88959 dig_frac = -1;
88960 dig_expt = -1;
88961 expt = 0;
88962 expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
88963 expt_neg = 0;
88964 for (;;) {
88965 ch = *p++;
88966
88967 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
88968 "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
88969 (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
88970 (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
88971 (long) dig_expt, (long) dig_lzero, (long) dig_prec));
88972 DUK__BI_PRINT("f", &nc_ctx->f);
88973
88974 /* Most common cases first. */
88975 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
88976 dig = (duk_small_int_t) ch - '0' + 0;
88977 } else if (ch == (duk_small_int_t) '.') {
88978 /* A leading digit is not required in some cases, e.g. accept ".123".
88979 * In other cases (JSON.parse()) a leading digit is required. This
88980 * is checked for after the loop.
88981 */
88982 if (dig_frac >= 0 || dig_expt >= 0) {
88983 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
88984 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
88985 break;
88986 } else {
88987 DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
88988 goto parse_fail;
88989 }
88990 }
88991
88992 if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) {
88993 /* Some contexts don't allow fractions at all; this can't be a
88994 * post-check because the state ('f' and expt) would be incorrect.
88995 */
88996 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
88997 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
88998 break;
88999 } else {
89000 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
89001 }
89002 }
89003
89004 DUK_DDD(DUK_DDDPRINT("start fraction part"));
89005 dig_frac = 0;
89006 continue;
89007 } else if (ch == (duk_small_int_t) 0) {
89008 DUK_DDD(DUK_DDDPRINT("NUL termination"));
89009 break;
89010 } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) &&
89011 dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
89012 /* Note: we don't parse back exponent notation for anything else
89013 * than radix 10, so this is not an ambiguous check (e.g. hex
89014 * exponent values may have 'e' either as a significand digit
89015 * or as an exponent separator).
89016 *
89017 * If the exponent separator occurs twice, 'e' will be interpreted
89018 * as a digit (= 14) and will be rejected as an invalid decimal
89019 * digit.
89020 */
89021
89022 DUK_DDD(DUK_DDDPRINT("start exponent part"));
89023
89024 /* Exponent without a sign or with a +/- sign is accepted
89025 * by all call sites (even JSON.parse()).
89026 */
89027 ch = *p;
89028 if (ch == (duk_small_int_t) '-') {
89029 expt_neg = 1;
89030 p++;
89031 } else if (ch == (duk_small_int_t) '+') {
89032 p++;
89033 }
89034 dig_expt = 0;
89035 continue;
89036 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
89037 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
89038 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
89039 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
89040 } else {
89041 dig = 255; /* triggers garbage digit check below */
89042 }
89043 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
89044
89045 if (dig >= radix) {
89046 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
89047 DUK_DDD(DUK_DDDPRINT("garbage termination"));
89048 break;
89049 } else {
89050 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
89051 goto parse_fail;
89052 }
89053 }
89054
89055 if (dig_expt < 0) {
89056 /* whole or fraction digit */
89057
89058 if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
89059 /* significant from precision perspective */
89060
89061 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
89062 if (f_zero && dig == 0) {
89063 /* Leading zero is not counted towards precision digits; not
89064 * in the integer part, nor in the fraction part.
89065 */
89066 if (dig_frac < 0) {
89067 dig_lzero++;
89068 }
89069 } else {
89070 /* XXX: join these ops (multiply-accumulate), but only if
89071 * code footprint decreases.
89072 */
89073 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix);
89074 duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig);
89075 dig_prec++;
89076 }
89077 } else {
89078 /* Ignore digits beyond a radix-specific limit, but note them
89079 * in expt_adj.
89080 */
89081 expt_adj++;
89082 }
89083
89084 if (dig_frac >= 0) {
89085 dig_frac++;
89086 expt_adj--;
89087 } else {
89088 dig_whole++;
89089 }
89090 } else {
89091 /* exponent digit */
89092
89093 DUK_ASSERT(radix == 10);
89094 expt = expt * radix + dig;
89095 if (expt > DUK_S2N_MAX_EXPONENT) {
89096 /* Impose a reasonable exponent limit, so that exp
89097 * doesn't need to get tracked using a bigint.
89098 */
89099 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
89100 goto parse_explimit_error;
89101 }
89102 dig_expt++;
89103 }
89104 }
89105
89106 /* Leading zero. */
89107
89108 if (dig_lzero > 0 && dig_whole > 1) {
89109 if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) {
89110 DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
89111 goto parse_fail;
89112 }
89113 }
89114
89115 /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
89116
89117 if (dig_whole == 0) {
89118 if (dig_frac == 0) {
89119 /* "." is not accepted in any format */
89120 DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
89121 goto parse_fail;
89122 } else if (dig_frac > 0) {
89123 /* ".123" */
89124 if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) {
89125 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
89126 "leading integer digit(s)"));
89127 goto parse_fail;
89128 }
89129 } else {
89130 /* Empty ("") is allowed in some formats (e.g. Number(''), as zero,
89131 * but it must not have a leading +/- sign (GH-2019). Note that
89132 * for Number(), h_str is already trimmed so we can check for zero
89133 * length and still get Number(' + ') == NaN.
89134 */
89135 if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) {
89136 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
89137 goto parse_fail;
89138 } else if (DUK_HSTRING_GET_BYTELEN(h_str) != 0) {
89139 DUK_DDD(DUK_DDDPRINT("parse failed: no digits, but not empty (had a +/- sign)"));
89140 goto parse_fail;
89141 }
89142 }
89143 } else {
89144 if (dig_frac == 0) {
89145 /* "123." is allowed in some formats */
89146 if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) {
89147 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
89148 goto parse_fail;
89149 }
89150 } else if (dig_frac > 0) {
89151 /* "123.456" */
89152 ;
89153 } else {
89154 /* "123" */
89155 ;
89156 }
89157 }
89158
89159 /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
89160 * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
89161 */
89162
89163 if (dig_expt == 0) {
89164 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) {
89165 DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
89166 goto parse_fail;
89167 }
89168 DUK_ASSERT(expt == 0);
89169 }
89170
89171 if (expt_neg) {
89172 expt = -expt;
89173 }
89174 DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
89175 (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
89176 expt += expt_adj;
89177
89178 /* Fast path check. */
89179
89180 if (nc_ctx->f.n <= 1 && /* 32-bit value */
89181 expt == 0 /* no net exponent */) {
89182 /* Fast path is triggered for no exponent and also for balanced exponent
89183 * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
89184 * zero sign.
89185 */
89186
89187 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
89188 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
89189 if (nc_ctx->f.n == 1) {
89190 res = (double) nc_ctx->f.v[0];
89191 } else {
89192 res = 0.0;
89193 }
89194 goto negcheck_and_ret;
89195 }
89196
89197 /* Significand ('f') padding. */
89198
89199 while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
89200 /* Pad significand with "virtual" zero digits so that Dragon4 will
89201 * have enough (apparent) precision to work with.
89202 */
89203 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
89204 duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1);
89205 DUK__BI_PRINT("f", &nc_ctx->f);
89206 expt--;
89207 dig_prec++;
89208 }
89209
89210 DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
89211
89212 /* Detect zero special case. */
89213
89214 if (nc_ctx->f.n == 0) {
89215 /* This may happen even after the fast path check, if exponent is
89216 * not balanced (e.g. "0e1"). Remember to respect zero sign.
89217 */
89218 DUK_DDD(DUK_DDDPRINT("significand is zero"));
89219 res = 0.0;
89220 goto negcheck_and_ret;
89221 }
89222
89223
89224 /* Quick reject of too large or too small exponents. This check
89225 * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
89226 * so zero check must be above.
89227 */
89228
89229 explim = &duk__str2num_exp_limits[radix - 2];
89230 if (expt > explim->upper) {
89231 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
89232 res = (duk_double_t) DUK_DOUBLE_INFINITY;
89233 goto negcheck_and_ret;
89234 } else if (expt < explim->lower) {
89235 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
89236 res = (duk_double_t) 0.0;
89237 goto negcheck_and_ret;
89238 }
89239
89240 nc_ctx->is_s2n = 1;
89241 nc_ctx->e = expt;
89242 nc_ctx->b = radix;
89243 nc_ctx->B = 2;
89244 nc_ctx->is_fixed = 1;
89245 nc_ctx->abs_pos = 0;
89246 nc_ctx->req_digits = 53 + 1;
89247
89248 DUK__BI_PRINT("f", &nc_ctx->f);
89249 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
89250
89251 /*
89252 * Dragon4 slow path (binary) digit generation.
89253 * An extra digit is generated for rounding.
89254 */
89255
89256 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
89257
89258 DUK_DDD(DUK_DDDPRINT("after prepare:"));
89259 DUK__BI_PRINT("r", &nc_ctx->r);
89260 DUK__BI_PRINT("s", &nc_ctx->s);
89261 DUK__BI_PRINT("mp", &nc_ctx->mp);
89262 DUK__BI_PRINT("mm", &nc_ctx->mm);
89263
89264 duk__dragon4_scale(nc_ctx);
89265
89266 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
89267 DUK__BI_PRINT("r", &nc_ctx->r);
89268 DUK__BI_PRINT("s", &nc_ctx->s);
89269 DUK__BI_PRINT("mp", &nc_ctx->mp);
89270 DUK__BI_PRINT("mm", &nc_ctx->mm);
89271
89272 duk__dragon4_generate(nc_ctx);
89273
89274 DUK_ASSERT(nc_ctx->count == 53 + 1);
89275
89276 /*
89277 * Convert binary digits into an IEEE double. Need to handle
89278 * denormals and rounding correctly.
89279 *
89280 * Some call sites currently assume the result is always a
89281 * non-fastint double. If this is changed, check all call
89282 * sites.
89283 */
89284
89285 duk__dragon4_ctx_to_double(nc_ctx, &res);
89286 goto negcheck_and_ret;
89287
89288 negcheck_and_ret:
89289 if (neg) {
89290 res = -res;
89291 }
89292 duk_pop(thr);
89293 duk_push_number(thr, (double) res);
89294 DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
89295 return;
89296
89297 parse_fail:
89298 DUK_DDD(DUK_DDDPRINT("parse failed"));
89299 duk_pop(thr);
89300 duk_push_nan(thr);
89301 return;
89302
89303 parse_explimit_error:
89304 DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
89305 DUK_ERROR_RANGE(thr, "exponent too large");
89306 DUK_WO_NORETURN(return;);
89307}
89308
89309DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) {
89310 duk_native_stack_check(thr);
89311 duk__numconv_parse_raw(thr, radix, flags);
89312}
89313
89314/* automatic undefs */
89315#undef DUK__BI_MAX_PARTS
89316#undef DUK__BI_PRINT
89317#undef DUK__DIGITCHAR
89318#undef DUK__DRAGON4_OUTPUT_PREINC
89319#undef DUK__IEEE_DOUBLE_EXP_BIAS
89320#undef DUK__IEEE_DOUBLE_EXP_MIN
89321#undef DUK__MAX_FORMATTED_LENGTH
89322#undef DUK__MAX_OUTPUT_DIGITS
89323#undef DUK__NO_EXP
89324#undef DUK__NUMCONV_CTX_BIGINTS_SIZE
89325#undef DUK__NUMCONV_CTX_NUM_BIGINTS
89326#line 1 "duk_regexp_compiler.c"
89327/*
89328 * Regexp compilation.
89329 *
89330 * See doc/regexp.rst for a discussion of the compilation approach and
89331 * current limitations.
89332 *
89333 * Regexp bytecode assumes jumps can be expressed with signed 32-bit
89334 * integers. Consequently the bytecode size must not exceed 0x7fffffffL.
89335 * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
89336 * in many places. Although this could be changed, the bytecode format
89337 * limit would still prevent regexps exceeding the signed 32-bit limit
89338 * from working.
89339 *
89340 * XXX: The implementation does not prevent bytecode from exceeding the
89341 * maximum supported size. This could be done by limiting the maximum
89342 * input string size (assuming an upper bound can be computed for number
89343 * of bytecode bytes emitted per input byte) or checking buffer maximum
89344 * size when emitting bytecode (slower).
89345 */
89346
89347/* #include duk_internal.h -> already included */
89348
89349#if defined(DUK_USE_REGEXP_SUPPORT)
89350
89351/*
89352 * Helper macros
89353 */
89354
89355#define DUK__RE_INITIAL_BUFSIZE 64
89356
89357#define DUK__RE_BUFLEN(re_ctx) \
89358 DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
89359
89360/*
89361 * Disjunction struct: result of parsing a disjunction
89362 */
89363
89364typedef struct {
89365 /* Number of characters that the atom matches (e.g. 3 for 'abc'),
89366 * -1 if atom is complex and number of matched characters either
89367 * varies or is not known.
89368 */
89369 duk_int32_t charlen;
89370
89371#if 0
89372 /* These are not needed to implement quantifier capture handling,
89373 * but might be needed at some point.
89374 */
89375
89376 /* re_ctx->captures at start and end of atom parsing.
89377 * Since 'captures' indicates highest capture number emitted
89378 * so far in a DUK_REOP_SAVE, the captures numbers saved by
89379 * the atom are: ]start_captures,end_captures].
89380 */
89381 duk_uint32_t start_captures;
89382 duk_uint32_t end_captures;
89383#endif
89384} duk__re_disjunction_info;
89385
89386/*
89387 * Encoding helpers
89388 *
89389 * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
89390 * even though the buffer operations will use duk_size_t.
89391 */
89392
89393/* XXX: the insert helpers should ensure that the bytecode result is not
89394 * larger than expected (or at least assert for it). Many things in the
89395 * bytecode, like skip offsets, won't work correctly if the bytecode is
89396 * larger than say 2G.
89397 */
89398
89399DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
89400 if (x < 0) {
89401 return ((duk_uint32_t) (-x)) * 2 + 1;
89402 } else {
89403 return ((duk_uint32_t) x) * 2;
89404 }
89405}
89406
89407/* XXX: return type should probably be duk_size_t, or explicit checks are needed for
89408 * maximum size.
89409 */
89410DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
89411 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
89412 duk_small_int_t len;
89413
89414 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
89415 DUK_ASSERT(len >= 0);
89416 DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len);
89417 return (duk_uint32_t) len;
89418}
89419
89420DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
89421 DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x);
89422}
89423
89424DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
89425#if defined(DUK_USE_PREFER_SIZE)
89426 duk__append_u32(re_ctx, x);
89427#else
89428 DUK_ASSERT(x <= 0x7fU);
89429 DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x);
89430#endif
89431}
89432
89433#if 0
89434DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) {
89435 DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y);
89436}
89437#endif
89438
89439DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
89440 return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
89441}
89442
89443DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) {
89444 DUK_ASSERT(reop <= 0x7fU);
89445 (void) duk__append_7bit(re_ctx, reop);
89446}
89447
89448#if 0 /* unused */
89449DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
89450 duk__append_u32(re_ctx, duk__encode_i32(x));
89451}
89452#endif
89453
89454/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
89455DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
89456 /* Call sites don't need the result length so it's not accumulated. */
89457 while (count-- > 0) {
89458 duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
89459 }
89460}
89461
89462DUK_LOCAL void duk__insert_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t data_offset, duk_uint32_t data_length) {
89463 DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
89464}
89465
89466DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
89467 DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
89468}
89469
89470DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
89471 DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
89472}
89473
89474/*
89475 * Insert a jump offset at 'offset' to complete an instruction
89476 * (the jump offset is always the last component of an instruction).
89477 * The 'skip' argument must be computed relative to 'offset',
89478 * -without- taking into account the skip field being inserted.
89479 *
89480 * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc)
89481 * => ... A B C ins SKIP X Y Z
89482 *
89483 * Computing the final (adjusted) skip value, which is relative to the
89484 * first byte of the next instruction, is a bit tricky because of the
89485 * variable length UTF-8 encoding. See doc/regexp.rst for discussion.
89486 */
89487DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
89488#if 0
89489 /* Iterative solution. */
89490 if (skip < 0) {
89491 duk_small_int_t len;
89492 /* two encoding attempts suffices */
89493 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
89494 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
89495 DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
89496 skip -= (duk_int32_t) len;
89497 }
89498#endif
89499
89500#if defined(DUK_USE_PREFER_SIZE)
89501 /* Closed form solution, this produces smallest code.
89502 * See re_neg_jump_offset (closed2).
89503 */
89504 if (skip < 0) {
89505 skip--;
89506 if (skip < -0x3fL) {
89507 skip--;
89508 }
89509 if (skip < -0x3ffL) {
89510 skip--;
89511 }
89512 if (skip < -0x7fffL) {
89513 skip--;
89514 }
89515 if (skip < -0xfffffL) {
89516 skip--;
89517 }
89518 if (skip < -0x1ffffffL) {
89519 skip--;
89520 }
89521 if (skip < -0x3fffffffL) {
89522 skip--;
89523 }
89524 }
89525#else /* DUK_USE_PREFER_SIZE */
89526 /* Closed form solution, this produces fastest code.
89527 * See re_neg_jump_offset (closed1).
89528 */
89529 if (skip < 0) {
89530 if (skip >= -0x3eL) {
89531 skip -= 1;
89532 } else if (skip >= -0x3fdL) {
89533 skip -= 2;
89534 } else if (skip >= -0x7ffcL) {
89535 skip -= 3;
89536 } else if (skip >= -0xffffbL) {
89537 skip -= 4;
89538 } else if (skip >= -0x1fffffaL) {
89539 skip -= 5;
89540 } else if (skip >= -0x3ffffff9L) {
89541 skip -= 6;
89542 } else {
89543 skip -= 7;
89544 }
89545 }
89546#endif /* DUK_USE_PREFER_SIZE */
89547
89548 return duk__insert_i32(re_ctx, offset, skip);
89549}
89550
89551DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
89552 return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
89553}
89554
89555/*
89556 * duk_re_range_callback for generating character class ranges.
89557 *
89558 * When ignoreCase is false, the range is simply emitted as is. We don't,
89559 * for instance, eliminate duplicates or overlapping ranges in a character
89560 * class.
89561 *
89562 * When ignoreCase is true but the 'direct' flag is set, the caller knows
89563 * that the range canonicalizes to itself for case insensitive matching,
89564 * so the range is emitted as is. This is mainly useful for built-in ranges
89565 * like \W.
89566 *
89567 * Otherwise, when ignoreCase is true, the range needs to be normalized
89568 * through canonicalization. Unfortunately a canonicalized version of a
89569 * continuous range is not necessarily continuous (e.g. [x-{] is continuous
89570 * but [X-{] is not). As a result, a single input range may expand to a lot
89571 * of output ranges. The current algorithm creates the canonicalized ranges
89572 * footprint efficiently at the cost of compile time execution time; see
89573 * doc/regexp.rst for discussion, and some more details below.
89574 *
89575 * Note that the ctx->nranges is a context-wide temporary value. This is OK
89576 * because there cannot be multiple character classes being parsed
89577 * simultaneously.
89578 *
89579 * More detail on canonicalization:
89580 *
89581 * Conceptually, a range is canonicalized by scanning the entire range,
89582 * normalizing each codepoint by converting it to uppercase, and generating
89583 * a set of result ranges.
89584 *
89585 * Ideally a minimal set of output ranges would be emitted by merging all
89586 * possible ranges even if they're emitted out of sequence. Because the
89587 * input string is also case normalized during matching, some codepoints
89588 * never occur at runtime; these "don't care" codepoints can be included or
89589 * excluded from ranges when merging/optimizing ranges.
89590 *
89591 * The current algorithm does not do optimal range merging. Rather, output
89592 * codepoints are generated in sequence, and when the output codepoints are
89593 * continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a
89594 * range as possible. A small canonicalization bitmap is used to reduce
89595 * actual codepoint canonicalizations which are quite slow at present. The
89596 * bitmap provides a "codepoint block is continuous with respect to
89597 * canonicalization" for N-codepoint blocks. This allows blocks to be
89598 * skipped quickly.
89599 *
89600 * There are a number of shortcomings and future work here:
89601 *
89602 * - Individual codepoint normalizations are slow because they involve
89603 * walking bit-packed rules without a lookup index.
89604 *
89605 * - The conceptual algorithm needs to canonicalize every codepoint in the
89606 * input range to figure out the output range(s). Even with the small
89607 * canonicalization bitmap the algorithm runs quite slowly for worst case
89608 * inputs. There are many data structure alternatives to improve this.
89609 *
89610 * - While the current algorithm generates maximal output ranges when the
89611 * output codepoints are emitted linearly, output ranges are not sorted or
89612 * merged otherwise. In the worst case a lot of ranges are emitted when
89613 * most of the ranges could be merged. In this process one could take
89614 * advantage of "don't care" codepoints, which are never matched against at
89615 * runtime due to canonicalization of input codepoints before comparison,
89616 * to merge otherwise discontinuous output ranges.
89617 *
89618 * - The runtime data structure is just a linear list of ranges to match
89619 * against. This can be quite slow if there are a lot of output ranges.
89620 * There are various ways to make matching against the ranges faster,
89621 * e.g. sorting the ranges and using a binary search; skip lists; tree
89622 * based representations; full or approximate codepoint bitmaps, etc.
89623 *
89624 * - Only BMP is supported, codepoints above BMP are assumed to canonicalize
89625 * to themselves. For now this is one place where we don't want to
89626 * support chars outside the BMP, because the exhaustive search would be
89627 * massively larger. It would be possible to support non-BMP with a
89628 * different algorithm, or perhaps doing case normalization only at match
89629 * time.
89630 */
89631
89632DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) {
89633 DUK_ASSERT(r2 >= r1);
89634 duk__append_u32(re_ctx, (duk_uint32_t) r1);
89635 duk__append_u32(re_ctx, (duk_uint32_t) r2);
89636 re_ctx->nranges++;
89637}
89638
89639#if defined(DUK_USE_REGEXP_CANON_BITMAP)
89640/* Find next canonicalization discontinuity (conservative estimate) starting
89641 * from 'start', not exceeding 'end'. If continuity is fine up to 'end'
89642 * inclusive, returns end. Minimum possible return value is start.
89643 */
89644DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
89645 duk_uint_t start_blk;
89646 duk_uint_t end_blk;
89647 duk_uint_t blk;
89648 duk_uint_t offset;
89649 duk_uint8_t mask;
89650
89651 /* Inclusive block range. */
89652 DUK_ASSERT(start >= 0);
89653 DUK_ASSERT(end >= 0);
89654 DUK_ASSERT(end >= start);
89655 start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT);
89656 end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT);
89657
89658 for (blk = start_blk; blk <= end_blk; blk++) {
89659 offset = blk >> 3;
89660 mask = 1U << (blk & 0x07);
89661 if (offset >= sizeof(duk_unicode_re_canon_bitmap)) {
89662 /* Reached non-BMP range which is assumed continuous. */
89663 return end;
89664 }
89665 DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap));
89666 if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) {
89667 /* Block is discontinuous, continuity is guaranteed
89668 * only up to end of previous block (+1 for exclusive
89669 * return value => start of current block). Start
89670 * block requires special handling.
89671 */
89672 if (blk > start_blk) {
89673 return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT);
89674 } else {
89675 return start;
89676 }
89677 }
89678 }
89679 DUK_ASSERT(blk == end_blk + 1); /* Reached end block which is continuous. */
89680 return end;
89681}
89682#else /* DUK_USE_REGEXP_CANON_BITMAP */
89683DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
89684 DUK_ASSERT(start >= 0);
89685 DUK_ASSERT(end >= 0);
89686 DUK_ASSERT(end >= start);
89687 if (start >= 0x10000) {
89688 /* Even without the bitmap, treat non-BMP as continuous. */
89689 return end;
89690 }
89691 return start;
89692}
89693#endif /* DUK_USE_REGEXP_CANON_BITMAP */
89694
89695DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
89696 duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
89697 duk_codepoint_t r_start;
89698 duk_codepoint_t r_end;
89699 duk_codepoint_t i;
89700 duk_codepoint_t t;
89701 duk_codepoint_t r_disc;
89702
89703 DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
89704 (void *) re_ctx, (long) r1, (long) r2, (long) direct));
89705
89706 DUK_ASSERT(r2 >= r1); /* SyntaxError for out of order range. */
89707
89708 if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) {
89709 DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]", (long) r1, (long) r2));
89710 duk__regexp_emit_range(re_ctx, r1, r2);
89711 return;
89712 }
89713
89714 DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]", (long) r1, (long) r2));
89715
89716 r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
89717 r_end = r_start;
89718
89719 for (i = r1 + 1; i <= r2;) {
89720 /* Input codepoint space processed up to i-1, and
89721 * current range in r_{start,end} is up-to-date
89722 * (inclusive) and may either break or continue.
89723 */
89724 r_disc = duk__re_canon_next_discontinuity(i, r2);
89725 DUK_ASSERT(r_disc >= i);
89726 DUK_ASSERT(r_disc <= r2);
89727
89728 r_end += r_disc - i; /* May be zero. */
89729 t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc);
89730 if (t == r_end + 1) {
89731 /* Not actually a discontinuity, continue range
89732 * to r_disc and recheck.
89733 */
89734 r_end = t;
89735 } else {
89736 duk__regexp_emit_range(re_ctx, r_start, r_end);
89737 r_start = t;
89738 r_end = t;
89739 }
89740 i = r_disc + 1; /* Guarantees progress. */
89741 }
89742 duk__regexp_emit_range(re_ctx, r_start, r_end);
89743
89744#if 0 /* Exhaustive search, very slow. */
89745 r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
89746 r_end = r_start;
89747 for (i = r1 + 1; i <= r2; i++) {
89748 t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
89749 if (t == r_end + 1) {
89750 r_end = t;
89751 } else {
89752 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
89753 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
89754 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
89755 re_ctx->nranges++;
89756 r_start = t;
89757 r_end = t;
89758 }
89759 }
89760 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
89761 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
89762 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
89763 re_ctx->nranges++;
89764#endif
89765}
89766
89767/*
89768 * Parse regexp Disjunction. Most of regexp compilation happens here.
89769 *
89770 * Handles Disjunction, Alternative, and Term productions directly without
89771 * recursion. The only constructs requiring recursion are positive/negative
89772 * lookaheads, capturing parentheses, and non-capturing parentheses.
89773 *
89774 * The function determines whether the entire disjunction is a 'simple atom'
89775 * (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
89776 * returns the atom character length which is needed by the caller to keep
89777 * track of its own atom character length. A disjunction with more than one
89778 * alternative is never considered a simple atom (although in some cases
89779 * that might be the case).
89780 *
89781 * Return value: simple atom character length or < 0 if not a simple atom.
89782 * Appends the bytecode for the disjunction matcher to the end of the temp
89783 * buffer.
89784 *
89785 * Regexp top level structure is:
89786 *
89787 * Disjunction = Term*
89788 * | Term* | Disjunction
89789 *
89790 * Term = Assertion
89791 * | Atom
89792 * | Atom Quantifier
89793 *
89794 * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
89795 *
89796 * Notes:
89797 *
89798 * * Tracking of the 'simple-ness' of the current atom vs. the entire
89799 * disjunction are separate matters. For instance, the disjunction
89800 * may be complex, but individual atoms may be simple. Furthermore,
89801 * simple quantifiers are used whenever possible, even if the
89802 * disjunction as a whole is complex.
89803 *
89804 * * The estimate of whether an atom is simple is conservative now,
89805 * and it would be possible to expand it. For instance, captures
89806 * cause the disjunction to be marked complex, even though captures
89807 * -can- be handled by simple quantifiers with some minor modifications.
89808 *
89809 * * Disjunction 'tainting' as 'complex' is handled at the end of the
89810 * main for loop collectively for atoms. Assertions, quantifiers,
89811 * and '|' tokens need to taint the result manually if necessary.
89812 * Assertions cannot add to result char length, only atoms (and
89813 * quantifiers) can; currently quantifiers will taint the result
89814 * as complex though.
89815 */
89816
89817DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = {
89818 duk_unicode_re_ranges_digit,
89819 duk_unicode_re_ranges_white,
89820 duk_unicode_re_ranges_wordchar
89821};
89822DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = {
89823 sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)),
89824 sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)),
89825 sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t))
89826};
89827
89828DUK_LOCAL void duk__append_range_atom_matcher(duk_re_compiler_ctx *re_ctx, duk_small_uint_t re_op, const duk_uint16_t *ranges, duk_small_uint_t count) {
89829#if 0
89830 DUK_ASSERT(re_op <= 0x7fUL);
89831 DUK_ASSERT(count <= 0x7fUL);
89832 duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count);
89833#endif
89834 duk__append_reop(re_ctx, re_op);
89835 duk__append_7bit(re_ctx, count);
89836 duk__append_u16_list(re_ctx, ranges, count * 2);
89837}
89838
89839DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
89840 duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
89841 duk_int32_t atom_char_length = 0; /* negative -> complex atom */
89842 duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */
89843 duk_int32_t unpatched_disjunction_split = -1;
89844 duk_int32_t unpatched_disjunction_jump = -1;
89845 duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
89846 duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */
89847 duk__re_disjunction_info tmp_disj;
89848
89849 DUK_ASSERT(out_atom_info != NULL);
89850
89851 duk_native_stack_check(re_ctx->thr);
89852 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
89853 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
89854 DUK_WO_NORETURN(return;);
89855 }
89856 re_ctx->recursion_depth++;
89857
89858#if 0
89859 out_atom_info->start_captures = re_ctx->captures;
89860#endif
89861
89862 for (;;) {
89863 /* atom_char_length, atom_start_offset, atom_start_offset reflect the
89864 * atom matched on the previous loop. If a quantifier is encountered
89865 * on this loop, these are needed to handle the quantifier correctly.
89866 * new_atom_char_length etc are for the atom parsed on this round;
89867 * they're written to atom_char_length etc at the end of the round.
89868 */
89869 duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */
89870 duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop
89871 * (allows quantifiers to copy the atom bytecode)
89872 */
89873 duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */
89874
89875 duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
89876
89877 DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
89878 (long) re_ctx->curr_token.t,
89879 (long) re_ctx->curr_token.num,
89880 (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
89881 (int) re_ctx->curr_token.num : (int) '?'));
89882
89883 /* set by atom case clauses */
89884 new_atom_start_offset = -1;
89885 new_atom_char_length = -1;
89886 new_atom_start_captures = re_ctx->captures;
89887
89888 switch (re_ctx->curr_token.t) {
89889 case DUK_RETOK_DISJUNCTION: {
89890 /*
89891 * The handling here is a bit tricky. If a previous '|' has been processed,
89892 * we have a pending split1 and a pending jump (for a previous match). These
89893 * need to be back-patched carefully. See docs for a detailed example.
89894 */
89895
89896 /* patch pending jump and split */
89897 if (unpatched_disjunction_jump >= 0) {
89898 duk_uint32_t offset;
89899
89900 DUK_ASSERT(unpatched_disjunction_split >= 0);
89901 offset = (duk_uint32_t) unpatched_disjunction_jump;
89902 offset += duk__insert_jump_offset(re_ctx,
89903 offset,
89904 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
89905 /* offset is now target of the pending split (right after jump) */
89906 duk__insert_jump_offset(re_ctx,
89907 (duk_uint32_t) unpatched_disjunction_split,
89908 (duk_int32_t) offset - unpatched_disjunction_split);
89909 }
89910
89911 /* add a new pending split to the beginning of the entire disjunction */
89912 (void) duk__insert_u32(re_ctx,
89913 entry_offset,
89914 DUK_REOP_SPLIT1); /* prefer direct execution */
89915 unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1); /* +1 for opcode */
89916
89917 /* add a new pending match jump for latest finished alternative */
89918 duk__append_reop(re_ctx, DUK_REOP_JUMP);
89919 unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
89920
89921 /* 'taint' result as complex */
89922 res_charlen = -1;
89923 break;
89924 }
89925 case DUK_RETOK_QUANTIFIER: {
89926 if (atom_start_offset < 0) {
89927 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
89928 DUK_WO_NORETURN(return;);
89929 }
89930 if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
89931 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
89932 DUK_WO_NORETURN(return;);
89933 }
89934 if (atom_char_length >= 0) {
89935 /*
89936 * Simple atom
89937 *
89938 * If atom_char_length is zero, we'll have unbounded execution time for e.g.
89939 * /()*x/.exec('x'). We can't just skip the match because it might have some
89940 * side effects (for instance, if we allowed captures in simple atoms, the
89941 * capture needs to happen). The simple solution below is to force the
89942 * quantifier to match at most once, since the additional matches have no effect.
89943 *
89944 * With a simple atom there can be no capture groups, so no captures need
89945 * to be reset.
89946 */
89947 duk_int32_t atom_code_length;
89948 duk_uint32_t offset;
89949 duk_uint32_t qmin, qmax;
89950
89951 qmin = re_ctx->curr_token.qmin;
89952 qmax = re_ctx->curr_token.qmax;
89953 if (atom_char_length == 0) {
89954 /* qmin and qmax will be 0 or 1 */
89955 if (qmin > 1) {
89956 qmin = 1;
89957 }
89958 if (qmax > 1) {
89959 qmax = 1;
89960 }
89961 }
89962
89963 duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
89964 atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset);
89965
89966 offset = (duk_uint32_t) atom_start_offset;
89967 if (re_ctx->curr_token.greedy) {
89968 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
89969 offset += duk__insert_u32(re_ctx, offset, qmin);
89970 offset += duk__insert_u32(re_ctx, offset, qmax);
89971 offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length);
89972 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
89973 } else {
89974 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
89975 offset += duk__insert_u32(re_ctx, offset, qmin);
89976 offset += duk__insert_u32(re_ctx, offset, qmax);
89977 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
89978 }
89979 DUK_UNREF(offset); /* silence scan-build warning */
89980 } else {
89981 /*
89982 * Complex atom
89983 *
89984 * The original code is used as a template, and removed at the end
89985 * (this differs from the handling of simple quantifiers).
89986 *
89987 * NOTE: there is no current solution for empty atoms in complex
89988 * quantifiers. This would need some sort of a 'progress' instruction.
89989 *
89990 * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
89991 */
89992 duk_int32_t atom_code_length;
89993 duk_uint32_t atom_copies;
89994 duk_uint32_t tmp_qmin, tmp_qmax;
89995
89996 /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
89997 atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
89998 re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
89999 if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
90000 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
90001 DUK_WO_NORETURN(return;);
90002 }
90003
90004 /* wipe the capture range made by the atom (if any) */
90005 DUK_ASSERT(atom_start_captures <= re_ctx->captures);
90006 if (atom_start_captures != re_ctx->captures) {
90007 DUK_ASSERT(atom_start_captures < re_ctx->captures);
90008 DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
90009 (long) atom_start_captures, (long) re_ctx->captures));
90010
90011 /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
90012 duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U);
90013 duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2);
90014 duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE);
90015 } else {
90016 DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
90017 (long) atom_start_captures));
90018 }
90019
90020 atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
90021
90022 /* insert the required matches (qmin) by copying the atom */
90023 tmp_qmin = re_ctx->curr_token.qmin;
90024 tmp_qmax = re_ctx->curr_token.qmax;
90025 while (tmp_qmin > 0) {
90026 duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
90027 tmp_qmin--;
90028 if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
90029 tmp_qmax--;
90030 }
90031 }
90032 DUK_ASSERT(tmp_qmin == 0);
90033
90034 /* insert code for matching the remainder - infinite or finite */
90035 if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
90036 /* reuse last emitted atom for remaining 'infinite' quantifier */
90037
90038 if (re_ctx->curr_token.qmin == 0) {
90039 /* Special case: original qmin was zero so there is nothing
90040 * to repeat. Emit an atom copy but jump over it here.
90041 */
90042 duk__append_reop(re_ctx, DUK_REOP_JUMP);
90043 duk__append_jump_offset(re_ctx, atom_code_length);
90044 duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
90045 }
90046 if (re_ctx->curr_token.greedy) {
90047 duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
90048 } else {
90049 duk__append_reop(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
90050 }
90051 duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
90052 } else {
90053 /*
90054 * The remaining matches are emitted as sequence of SPLITs and atom
90055 * copies; the SPLITs skip the remaining copies and match the sequel.
90056 * This sequence needs to be emitted starting from the last copy
90057 * because the SPLITs are variable length due to the variable length
90058 * skip offset. This causes a lot of memory copying now.
90059 *
90060 * Example structure (greedy, match maximum # atoms):
90061 *
90062 * SPLIT1 LSEQ
90063 * (atom)
90064 * SPLIT1 LSEQ ; <- the byte length of this instruction is needed
90065 * (atom) ; to encode the above SPLIT1 correctly
90066 * ...
90067 * LSEQ:
90068 */
90069 duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
90070 while (tmp_qmax > 0) {
90071 duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
90072 if (re_ctx->curr_token.greedy) {
90073 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
90074 } else {
90075 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */
90076 }
90077 duk__insert_jump_offset(re_ctx,
90078 offset + 1, /* +1 for opcode */
90079 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
90080 tmp_qmax--;
90081 }
90082 }
90083
90084 /* remove the original 'template' atom */
90085 duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
90086 }
90087
90088 /* 'taint' result as complex */
90089 res_charlen = -1;
90090 break;
90091 }
90092 case DUK_RETOK_ASSERT_START: {
90093 duk__append_reop(re_ctx, DUK_REOP_ASSERT_START);
90094 break;
90095 }
90096 case DUK_RETOK_ASSERT_END: {
90097 duk__append_reop(re_ctx, DUK_REOP_ASSERT_END);
90098 break;
90099 }
90100 case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
90101 duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
90102 break;
90103 }
90104 case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
90105 duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
90106 break;
90107 }
90108 case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
90109 case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
90110 duk_uint32_t offset;
90111 duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
90112 DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
90113
90114 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
90115 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
90116 duk__append_reop(re_ctx, DUK_REOP_MATCH);
90117
90118 (void) duk__insert_u32(re_ctx, offset, opcode);
90119 (void) duk__insert_jump_offset(re_ctx,
90120 offset + 1, /* +1 for opcode */
90121 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
90122
90123 /* 'taint' result as complex -- this is conservative,
90124 * as lookaheads do not backtrack.
90125 */
90126 res_charlen = -1;
90127 break;
90128 }
90129 case DUK_RETOK_ATOM_PERIOD: {
90130 new_atom_char_length = 1;
90131 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90132 duk__append_reop(re_ctx, DUK_REOP_PERIOD);
90133 break;
90134 }
90135 case DUK_RETOK_ATOM_CHAR: {
90136 /* Note: successive characters could be joined into string matches
90137 * but this is not trivial (consider e.g. '/xyz+/); see docs for
90138 * more discussion.
90139 *
90140 * No support for \u{H+} yet. While only BMP Unicode escapes are
90141 * supported for RegExps at present, 'ch' may still be a non-BMP
90142 * codepoint if it is decoded straight from source text UTF-8.
90143 * There's no non-BMP support yet so this is handled simply by
90144 * matching the non-BMP character (which is custom behavior).
90145 */
90146 duk_uint32_t ch;
90147
90148 new_atom_char_length = 1;
90149 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90150 duk__append_reop(re_ctx, DUK_REOP_CHAR);
90151 ch = re_ctx->curr_token.num;
90152 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
90153 ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch);
90154 }
90155 duk__append_u32(re_ctx, ch);
90156 break;
90157 }
90158 case DUK_RETOK_ATOM_DIGIT:
90159 case DUK_RETOK_ATOM_NOT_DIGIT:
90160 case DUK_RETOK_ATOM_WHITE:
90161 case DUK_RETOK_ATOM_NOT_WHITE:
90162 case DUK_RETOK_ATOM_WORD_CHAR:
90163 case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
90164 duk_small_uint_t re_op;
90165 duk_small_uint_t idx;
90166
90167 new_atom_char_length = 1;
90168 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90169
90170 DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0);
90171 DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0);
90172 DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0);
90173 DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0);
90174 DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0);
90175 DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0);
90176 re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES;
90177
90178 DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2);
90179 DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4);
90180 idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U);
90181 DUK_ASSERT(idx <= 2U); /* Assume continuous token numbers; also checks negative underflow. */
90182
90183 duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]);
90184 break;
90185 }
90186 case DUK_RETOK_ATOM_BACKREFERENCE: {
90187 duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
90188 if (backref > re_ctx->highest_backref) {
90189 re_ctx->highest_backref = backref;
90190 }
90191 new_atom_char_length = -1; /* mark as complex */
90192 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90193 duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE);
90194 duk__append_u32(re_ctx, backref);
90195 break;
90196 }
90197 case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
90198 duk_uint32_t cap;
90199
90200 new_atom_char_length = -1; /* mark as complex (capture handling) */
90201 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90202 cap = ++re_ctx->captures;
90203 duk__append_reop(re_ctx, DUK_REOP_SAVE);
90204 duk__append_u32(re_ctx, cap * 2);
90205 duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
90206 duk__append_reop(re_ctx, DUK_REOP_SAVE);
90207 duk__append_u32(re_ctx, cap * 2 + 1);
90208 break;
90209 }
90210 case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
90211 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90212 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
90213 new_atom_char_length = tmp_disj.charlen;
90214 break;
90215 }
90216 case DUK_RETOK_ATOM_START_CHARCLASS:
90217 case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
90218 /*
90219 * Range parsing is done with a special lexer function which calls
90220 * us for every range parsed. This is different from how rest of
90221 * the parsing works, but avoids a heavy, arbitrary size intermediate
90222 * value type to hold the ranges.
90223 *
90224 * Another complication is the handling of character ranges when
90225 * case insensitive matching is used (see docs for discussion).
90226 * The range handler callback given to the lexer takes care of this
90227 * as well.
90228 *
90229 * Note that duplicate ranges are not eliminated when parsing character
90230 * classes, so that canonicalization of
90231 *
90232 * [0-9a-fA-Fx-{]
90233 *
90234 * creates the result (note the duplicate ranges):
90235 *
90236 * [0-9A-FA-FX-Z{-{]
90237 *
90238 * where [x-{] is split as a result of canonicalization. The duplicate
90239 * ranges are not a semantics issue: they work correctly.
90240 */
90241
90242 duk_uint32_t offset;
90243
90244 DUK_DD(DUK_DDPRINT("character class"));
90245
90246 /* insert ranges instruction, range count patched in later */
90247 new_atom_char_length = 1;
90248 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
90249 duk__append_reop(re_ctx,
90250 (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
90251 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
90252 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
90253
90254 /* parse ranges until character class ends */
90255 re_ctx->nranges = 0; /* note: ctx-wide temporary */
90256 duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx);
90257
90258 /* insert range count */
90259 duk__insert_u32(re_ctx, offset, re_ctx->nranges);
90260 break;
90261 }
90262 case DUK_RETOK_ATOM_END_GROUP: {
90263 if (expect_eof) {
90264 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
90265 DUK_WO_NORETURN(return;);
90266 }
90267 goto done;
90268 }
90269 case DUK_RETOK_EOF: {
90270 if (!expect_eof) {
90271 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
90272 DUK_WO_NORETURN(return;);
90273 }
90274 goto done;
90275 }
90276 default: {
90277 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
90278 DUK_WO_NORETURN(return;);
90279 }
90280 }
90281
90282 /* a complex (new) atom taints the result */
90283 if (new_atom_start_offset >= 0) {
90284 if (new_atom_char_length < 0) {
90285 res_charlen = -1;
90286 } else if (res_charlen >= 0) {
90287 /* only advance if not tainted */
90288 res_charlen += new_atom_char_length;
90289 }
90290 }
90291
90292 /* record previous atom info in case next token is a quantifier */
90293 atom_start_offset = new_atom_start_offset;
90294 atom_char_length = new_atom_char_length;
90295 atom_start_captures = new_atom_start_captures;
90296 }
90297
90298 done:
90299
90300 /* finish up pending jump and split for last alternative */
90301 if (unpatched_disjunction_jump >= 0) {
90302 duk_uint32_t offset;
90303
90304 DUK_ASSERT(unpatched_disjunction_split >= 0);
90305 offset = (duk_uint32_t) unpatched_disjunction_jump;
90306 offset += duk__insert_jump_offset(re_ctx,
90307 offset,
90308 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
90309 /* offset is now target of the pending split (right after jump) */
90310 duk__insert_jump_offset(re_ctx,
90311 (duk_uint32_t) unpatched_disjunction_split,
90312 (duk_int32_t) offset - unpatched_disjunction_split);
90313 }
90314
90315#if 0
90316 out_atom_info->end_captures = re_ctx->captures;
90317#endif
90318 out_atom_info->charlen = res_charlen;
90319 DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
90320 (long) out_atom_info->charlen));
90321
90322 re_ctx->recursion_depth--;
90323}
90324
90325/*
90326 * Flags parsing (see E5 Section 15.10.4.1).
90327 */
90328
90329DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
90330 const duk_uint8_t *p;
90331 const duk_uint8_t *p_end;
90332 duk_uint32_t flags = 0;
90333
90334 p = DUK_HSTRING_GET_DATA(h);
90335 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
90336
90337 /* Note: can be safely scanned as bytes (undecoded) */
90338
90339 while (p < p_end) {
90340 duk_uint8_t c = *p++;
90341 switch (c) {
90342 case (duk_uint8_t) 'g': {
90343 if (flags & DUK_RE_FLAG_GLOBAL) {
90344 goto flags_error;
90345 }
90346 flags |= DUK_RE_FLAG_GLOBAL;
90347 break;
90348 }
90349 case (duk_uint8_t) 'i': {
90350 if (flags & DUK_RE_FLAG_IGNORE_CASE) {
90351 goto flags_error;
90352 }
90353 flags |= DUK_RE_FLAG_IGNORE_CASE;
90354 break;
90355 }
90356 case (duk_uint8_t) 'm': {
90357 if (flags & DUK_RE_FLAG_MULTILINE) {
90358 goto flags_error;
90359 }
90360 flags |= DUK_RE_FLAG_MULTILINE;
90361 break;
90362 }
90363 default: {
90364 goto flags_error;
90365 }
90366 }
90367 }
90368
90369 return flags;
90370
90371 flags_error:
90372 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
90373 DUK_WO_NORETURN(return 0U;);
90374}
90375
90376/*
90377 * Create escaped RegExp source (E5 Section 15.10.3).
90378 *
90379 * The current approach is to special case the empty RegExp
90380 * ('' -> '(?:)') and otherwise replace unescaped '/' characters
90381 * with '\/' regardless of where they occur in the regexp.
90382 *
90383 * Note that normalization does not seem to be necessary for
90384 * RegExp literals (e.g. '/foo/') because to be acceptable as
90385 * a RegExp literal, the text between forward slashes must
90386 * already match the escaping requirements (e.g. must not contain
90387 * unescaped forward slashes or be empty). Escaping IS needed
90388 * for expressions like 'new Regexp("...", "")' however.
90389 * Currently, we re-escape in either case.
90390 *
90391 * Also note that we process the source here in UTF-8 encoded
90392 * form. This is correct, because any non-ASCII characters are
90393 * passed through without change.
90394 */
90395
90396DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
90397 duk_hstring *h;
90398 const duk_uint8_t *p;
90399 duk_bufwriter_ctx bw_alloc;
90400 duk_bufwriter_ctx *bw;
90401 duk_uint8_t *q;
90402 duk_size_t i, n;
90403 duk_uint_fast8_t c_prev, c;
90404
90405 h = duk_known_hstring(thr, idx_pattern);
90406 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
90407 n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
90408
90409 if (n == 0) {
90410 duk_push_literal(thr, "(?:)");
90411 return;
90412 }
90413
90414 bw = &bw_alloc;
90415 DUK_BW_INIT_PUSHBUF(thr, bw, n);
90416 q = DUK_BW_GET_PTR(thr, bw);
90417
90418 c_prev = (duk_uint_fast8_t) 0;
90419
90420 for (i = 0; i < n; i++) {
90421 c = p[i];
90422
90423 q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
90424
90425 if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
90426 /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
90427 * inside a character class, ...) => same escape works.
90428 */
90429 *q++ = DUK_ASC_BACKSLASH;
90430 }
90431 *q++ = (duk_uint8_t) c;
90432
90433 c_prev = c;
90434 }
90435
90436 DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
90437 (void) duk_buffer_to_string(thr, -1); /* Safe if input is safe. */
90438
90439 /* [ ... escaped_source ] */
90440}
90441
90442/*
90443 * Exposed regexp compilation primitive.
90444 *
90445 * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
90446 * actual parsing. Handles generation of the compiled regexp header and the
90447 * "boilerplate" capture of the matching substring (save 0 and 1). Also does some
90448 * global level regexp checks after recursive compilation has finished.
90449 *
90450 * An escaped version of the regexp source, suitable for use as a RegExp instance
90451 * 'source' property (see E5 Section 15.10.3), is also left on the stack.
90452 *
90453 * Input stack: [ pattern flags ]
90454 * Output stack: [ bytecode escaped_source ] (both as strings)
90455 */
90456
90457DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
90458 duk_re_compiler_ctx re_ctx;
90459 duk_lexer_point lex_point;
90460 duk_hstring *h_pattern;
90461 duk_hstring *h_flags;
90462 duk__re_disjunction_info ign_disj;
90463
90464 DUK_ASSERT(thr != NULL);
90465
90466 /*
90467 * Args validation
90468 */
90469
90470 /* TypeError if fails */
90471 h_pattern = duk_require_hstring_notsymbol(thr, -2);
90472 h_flags = duk_require_hstring_notsymbol(thr, -1);
90473
90474 /*
90475 * Create normalized 'source' property (E5 Section 15.10.3).
90476 */
90477
90478 /* [ ... pattern flags ] */
90479
90480 duk__create_escaped_source(thr, -2);
90481
90482 /* [ ... pattern flags escaped_source ] */
90483
90484 /*
90485 * Init compilation context
90486 */
90487
90488 /* [ ... pattern flags escaped_source buffer ] */
90489
90490 duk_memzero(&re_ctx, sizeof(re_ctx));
90491 DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */
90492 re_ctx.thr = thr;
90493 re_ctx.lex.thr = thr;
90494 re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
90495 re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
90496 re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
90497 re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
90498 re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
90499
90500 DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
90501
90502 DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
90503 (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
90504
90505 /*
90506 * Init lexer
90507 */
90508
90509 lex_point.offset = 0; /* expensive init, just want to fill window */
90510 lex_point.line = 1;
90511 DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
90512
90513 /*
90514 * Compilation
90515 */
90516
90517 DUK_DD(DUK_DDPRINT("starting regexp compilation"));
90518
90519 duk__append_reop(&re_ctx, DUK_REOP_SAVE);
90520 duk__append_7bit(&re_ctx, 0);
90521 duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
90522 duk__append_reop(&re_ctx, DUK_REOP_SAVE);
90523 duk__append_7bit(&re_ctx, 1);
90524 duk__append_reop(&re_ctx, DUK_REOP_MATCH);
90525
90526 /*
90527 * Check for invalid backreferences; note that it is NOT an error
90528 * to back-reference a capture group which has not yet been introduced
90529 * in the pattern (as in /\1(foo)/); in fact, the backreference will
90530 * always match! It IS an error to back-reference a capture group
90531 * which will never be introduced in the pattern. Thus, we can check
90532 * for such references only after parsing is complete.
90533 */
90534
90535 if (re_ctx.highest_backref > re_ctx.captures) {
90536 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
90537 DUK_WO_NORETURN(return;);
90538 }
90539
90540 /*
90541 * Emit compiled regexp header: flags, ncaptures
90542 * (insertion order inverted on purpose)
90543 */
90544
90545 duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
90546 duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
90547
90548 /* [ ... pattern flags escaped_source buffer ] */
90549
90550 DUK_BW_COMPACT(thr, &re_ctx.bw);
90551 (void) duk_buffer_to_string(thr, -1); /* Safe because flags is at most 7 bit. */
90552
90553 /* [ ... pattern flags escaped_source bytecode ] */
90554
90555 /*
90556 * Finalize stack
90557 */
90558
90559 duk_remove(thr, -4); /* -> [ ... flags escaped_source bytecode ] */
90560 duk_remove(thr, -3); /* -> [ ... escaped_source bytecode ] */
90561
90562 DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
90563 (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2)));
90564}
90565
90566/*
90567 * Create a RegExp instance (E5 Section 15.10.7).
90568 *
90569 * Note: the output stack left by duk_regexp_compile() is directly compatible
90570 * with the input here.
90571 *
90572 * Input stack: [ escaped_source bytecode ] (both as strings)
90573 * Output stack: [ RegExp ]
90574 */
90575
90576DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
90577 duk_hobject *h;
90578
90579 /* [ ... escaped_source bytecode ] */
90580
90581 duk_push_object(thr);
90582 h = duk_known_hobject(thr, -1);
90583 duk_insert(thr, -3);
90584
90585 /* [ ... regexp_object escaped_source bytecode ] */
90586
90587 DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
90588 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
90589
90590 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
90591
90592 /* [ ... regexp_object escaped_source ] */
90593
90594 /* In ES2015 .source, and the .global, .multiline, etc flags are
90595 * inherited getters. Store the escaped source as an internal
90596 * property for the getter.
90597 */
90598
90599 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
90600
90601 /* [ ... regexp_object ] */
90602
90603 duk_push_int(thr, 0);
90604 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
90605
90606 /* [ ... regexp_object ] */
90607}
90608
90609#else /* DUK_USE_REGEXP_SUPPORT */
90610
90611/* regexp support disabled */
90612
90613#endif /* DUK_USE_REGEXP_SUPPORT */
90614
90615/* automatic undefs */
90616#undef DUK__RE_BUFLEN
90617#undef DUK__RE_INITIAL_BUFSIZE
90618#line 1 "duk_regexp_executor.c"
90619/*
90620 * Regexp executor.
90621 *
90622 * Safety: the ECMAScript executor should prevent user from reading and
90623 * replacing regexp bytecode. Even so, the executor must validate all
90624 * memory accesses etc. When an invalid access is detected (e.g. a 'save'
90625 * opcode to invalid, unallocated index) it should fail with an internal
90626 * error but not cause a segmentation fault.
90627 *
90628 * Notes:
90629 *
90630 * - Backtrack counts are limited to unsigned 32 bits but should
90631 * technically be duk_size_t for strings longer than 4G chars.
90632 * This also requires a regexp bytecode change.
90633 */
90634
90635/* #include duk_internal.h -> already included */
90636
90637#if defined(DUK_USE_REGEXP_SUPPORT)
90638
90639/*
90640 * Helpers for UTF-8 handling
90641 *
90642 * For bytecode readers the duk_uint32_t and duk_int32_t types are correct
90643 * because they're used for more than just codepoints.
90644 */
90645
90646DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
90647 return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
90648}
90649
90650DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
90651 duk_uint32_t t;
90652
90653 /* signed integer encoding needed to work with UTF-8 */
90654 t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
90655 if (t & 1) {
90656 return -((duk_int32_t) (t >> 1));
90657 } else {
90658 return (duk_int32_t) (t >> 1);
90659 }
90660}
90661
90662DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
90663 const duk_uint8_t *p;
90664
90665 /* Note: allow backtracking from p == ptr_end */
90666 p = *ptr;
90667 if (p < ptr_start || p > ptr_end) {
90668 goto fail;
90669 }
90670
90671 while (count > 0) {
90672 for (;;) {
90673 p--;
90674 if (p < ptr_start) {
90675 goto fail;
90676 }
90677 if ((*p & 0xc0) != 0x80) {
90678 /* utf-8 continuation bytes have the form 10xx xxxx */
90679 break;
90680 }
90681 }
90682 count--;
90683 }
90684 *ptr = p;
90685 return p;
90686
90687 fail:
90688 DUK_ERROR_INTERNAL(thr);
90689 DUK_WO_NORETURN(return NULL;);
90690}
90691
90692DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
90693 const duk_uint8_t *p;
90694
90695 p = *ptr;
90696 if (p < ptr_start || p >= ptr_end) {
90697 goto fail;
90698 }
90699
90700 while (count > 0) {
90701 for (;;) {
90702 p++;
90703
90704 /* Note: if encoding ends by hitting end of input, we don't check that
90705 * the encoding is valid, we just assume it is.
90706 */
90707 if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
90708 /* utf-8 continuation bytes have the form 10xx xxxx */
90709 break;
90710 }
90711 }
90712 count--;
90713 }
90714
90715 *ptr = p;
90716 return p;
90717
90718 fail:
90719 DUK_ERROR_INTERNAL(thr);
90720 DUK_WO_NORETURN(return NULL;);
90721}
90722
90723/*
90724 * Helpers for dealing with the input string
90725 */
90726
90727/* Get a (possibly canonicalized) input character from current sp. The input
90728 * itself is never modified, and captures always record non-canonicalized
90729 * characters even in case-insensitive matching. Return <0 if out of input.
90730 */
90731DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
90732 duk_codepoint_t res;
90733
90734 if (*sp >= re_ctx->input_end) {
90735 return -1;
90736 }
90737 res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
90738 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
90739 res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
90740 }
90741 return res;
90742}
90743
90744DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
90745 return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
90746}
90747
90748/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
90749DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
90750 /* note: caller 'sp' is intentionally not updated here */
90751 (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
90752 return duk__inp_get_cp(re_ctx, &sp);
90753}
90754
90755/*
90756 * Regexp recursive matching function.
90757 *
90758 * Returns 'sp' on successful match (points to character after last matched one),
90759 * NULL otherwise.
90760 *
90761 * The C recursion depth limit check is only performed in this function, this
90762 * suffices because the function is present in all true recursion required by
90763 * regexp execution.
90764 */
90765
90766DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
90767 duk_native_stack_check(re_ctx->thr);
90768 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
90769 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
90770 DUK_WO_NORETURN(return NULL;);
90771 }
90772 re_ctx->recursion_depth++;
90773
90774 for (;;) {
90775 duk_small_int_t op;
90776
90777 if (re_ctx->steps_count >= re_ctx->steps_limit) {
90778 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
90779 DUK_WO_NORETURN(return NULL;);
90780 }
90781 re_ctx->steps_count++;
90782
90783 /* Opcodes are at most 7 bits now so they encode to one byte. If this
90784 * were not the case or 'pc' is invalid here (due to a bug etc) we'll
90785 * still fail safely through the switch default case.
90786 */
90787 DUK_ASSERT(pc[0] <= 0x7fU);
90788#if 0
90789 op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
90790#endif
90791 op = *pc++;
90792
90793 DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
90794 (long) re_ctx->recursion_depth,
90795 (long) re_ctx->steps_count,
90796 (long) (pc - re_ctx->bytecode),
90797 (long) (sp - re_ctx->input),
90798 (long) op));
90799
90800 switch (op) {
90801 case DUK_REOP_MATCH: {
90802 goto match;
90803 }
90804 case DUK_REOP_CHAR: {
90805 /*
90806 * Byte-based matching would be possible for case-sensitive
90807 * matching but not for case-insensitive matching. So, we
90808 * match by decoding the input and bytecode character normally.
90809 *
90810 * Bytecode characters are assumed to be already canonicalized.
90811 * Input characters are canonicalized automatically by
90812 * duk__inp_get_cp() if necessary.
90813 *
90814 * There is no opcode for matching multiple characters. The
90815 * regexp compiler has trouble joining strings efficiently
90816 * during compilation. See doc/regexp.rst for more discussion.
90817 */
90818 duk_codepoint_t c1, c2;
90819
90820 c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
90821 DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
90822 c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
90823 c2 = duk__inp_get_cp(re_ctx, &sp);
90824 /* No need to check for c2 < 0 (end of input): because c1 >= 0, it
90825 * will fail the match below automatically and cause goto fail.
90826 */
90827#if 0
90828 if (c2 < 0) {
90829 goto fail;
90830 }
90831#endif
90832 DUK_ASSERT(c1 >= 0);
90833
90834 DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
90835 if (c1 != c2) {
90836 goto fail;
90837 }
90838 break;
90839 }
90840 case DUK_REOP_PERIOD: {
90841 duk_codepoint_t c;
90842
90843 c = duk__inp_get_cp(re_ctx, &sp);
90844 if (c < 0 || duk_unicode_is_line_terminator(c)) {
90845 /* E5 Sections 15.10.2.8, 7.3 */
90846 goto fail;
90847 }
90848 break;
90849 }
90850 case DUK_REOP_RANGES:
90851 case DUK_REOP_INVRANGES: {
90852 duk_uint32_t n;
90853 duk_codepoint_t c;
90854 duk_small_int_t match;
90855
90856 n = duk__bc_get_u32(re_ctx, &pc);
90857 c = duk__inp_get_cp(re_ctx, &sp);
90858 if (c < 0) {
90859 goto fail;
90860 }
90861
90862 match = 0;
90863 while (n) {
90864 duk_codepoint_t r1, r2;
90865 r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
90866 r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
90867 DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
90868 (long) n, (long) r1, (long) r2, (long) c));
90869 if (c >= r1 && c <= r2) {
90870 /* Note: don't bail out early, we must read all the ranges from
90871 * bytecode. Another option is to skip them efficiently after
90872 * breaking out of here. Prefer smallest code.
90873 */
90874 match = 1;
90875 }
90876 n--;
90877 }
90878
90879 if (op == DUK_REOP_RANGES) {
90880 if (!match) {
90881 goto fail;
90882 }
90883 } else {
90884 DUK_ASSERT(op == DUK_REOP_INVRANGES);
90885 if (match) {
90886 goto fail;
90887 }
90888 }
90889 break;
90890 }
90891 case DUK_REOP_ASSERT_START: {
90892 duk_codepoint_t c;
90893
90894 if (sp <= re_ctx->input) {
90895 break;
90896 }
90897 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
90898 goto fail;
90899 }
90900 c = duk__inp_get_prev_cp(re_ctx, sp);
90901 if (duk_unicode_is_line_terminator(c)) {
90902 /* E5 Sections 15.10.2.8, 7.3 */
90903 break;
90904 }
90905 goto fail;
90906 }
90907 case DUK_REOP_ASSERT_END: {
90908 duk_codepoint_t c;
90909 const duk_uint8_t *tmp_sp;
90910
90911 tmp_sp = sp;
90912 c = duk__inp_get_cp(re_ctx, &tmp_sp);
90913 if (c < 0) {
90914 break;
90915 }
90916 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
90917 goto fail;
90918 }
90919 if (duk_unicode_is_line_terminator(c)) {
90920 /* E5 Sections 15.10.2.8, 7.3 */
90921 break;
90922 }
90923 goto fail;
90924 }
90925 case DUK_REOP_ASSERT_WORD_BOUNDARY:
90926 case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
90927 /*
90928 * E5 Section 15.10.2.6. The previous and current character
90929 * should -not- be canonicalized as they are now. However,
90930 * canonicalization does not affect the result of IsWordChar()
90931 * (which depends on Unicode characters never canonicalizing
90932 * into ASCII characters) so this does not matter.
90933 */
90934 duk_small_int_t w1, w2;
90935
90936 if (sp <= re_ctx->input) {
90937 w1 = 0; /* not a wordchar */
90938 } else {
90939 duk_codepoint_t c;
90940 c = duk__inp_get_prev_cp(re_ctx, sp);
90941 w1 = duk_unicode_re_is_wordchar(c);
90942 }
90943 if (sp >= re_ctx->input_end) {
90944 w2 = 0; /* not a wordchar */
90945 } else {
90946 const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */
90947 duk_codepoint_t c;
90948 c = duk__inp_get_cp(re_ctx, &tmp_sp);
90949 w2 = duk_unicode_re_is_wordchar(c);
90950 }
90951
90952 if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
90953 if (w1 == w2) {
90954 goto fail;
90955 }
90956 } else {
90957 DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
90958 if (w1 != w2) {
90959 goto fail;
90960 }
90961 }
90962 break;
90963 }
90964 case DUK_REOP_JUMP: {
90965 duk_int32_t skip;
90966
90967 skip = duk__bc_get_i32(re_ctx, &pc);
90968 pc += skip;
90969 break;
90970 }
90971 case DUK_REOP_SPLIT1: {
90972 /* split1: prefer direct execution (no jump) */
90973 const duk_uint8_t *sub_sp;
90974 duk_int32_t skip;
90975
90976 skip = duk__bc_get_i32(re_ctx, &pc);
90977 sub_sp = duk__match_regexp(re_ctx, pc, sp);
90978 if (sub_sp) {
90979 sp = sub_sp;
90980 goto match;
90981 }
90982 pc += skip;
90983 break;
90984 }
90985 case DUK_REOP_SPLIT2: {
90986 /* split2: prefer jump execution (not direct) */
90987 const duk_uint8_t *sub_sp;
90988 duk_int32_t skip;
90989
90990 skip = duk__bc_get_i32(re_ctx, &pc);
90991 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
90992 if (sub_sp) {
90993 sp = sub_sp;
90994 goto match;
90995 }
90996 break;
90997 }
90998 case DUK_REOP_SQMINIMAL: {
90999 duk_uint32_t q, qmin, qmax;
91000 duk_int32_t skip;
91001 const duk_uint8_t *sub_sp;
91002
91003 qmin = duk__bc_get_u32(re_ctx, &pc);
91004 qmax = duk__bc_get_u32(re_ctx, &pc);
91005 skip = duk__bc_get_i32(re_ctx, &pc);
91006 DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
91007 (unsigned long) qmin, (unsigned long) qmax, (long) skip));
91008
91009 q = 0;
91010 while (q <= qmax) {
91011 if (q >= qmin) {
91012 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
91013 if (sub_sp) {
91014 sp = sub_sp;
91015 goto match;
91016 }
91017 }
91018 sub_sp = duk__match_regexp(re_ctx, pc, sp);
91019 if (!sub_sp) {
91020 break;
91021 }
91022 sp = sub_sp;
91023 q++;
91024 }
91025 goto fail;
91026 }
91027 case DUK_REOP_SQGREEDY: {
91028 duk_uint32_t q, qmin, qmax, atomlen;
91029 duk_int32_t skip;
91030 const duk_uint8_t *sub_sp;
91031
91032 qmin = duk__bc_get_u32(re_ctx, &pc);
91033 qmax = duk__bc_get_u32(re_ctx, &pc);
91034 atomlen = duk__bc_get_u32(re_ctx, &pc);
91035 skip = duk__bc_get_i32(re_ctx, &pc);
91036 DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
91037 (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
91038
91039 q = 0;
91040 while (q < qmax) {
91041 sub_sp = duk__match_regexp(re_ctx, pc, sp);
91042 if (!sub_sp) {
91043 break;
91044 }
91045 sp = sub_sp;
91046 q++;
91047 }
91048 while (q >= qmin) {
91049 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
91050 if (sub_sp) {
91051 sp = sub_sp;
91052 goto match;
91053 }
91054 if (q == qmin) {
91055 break;
91056 }
91057
91058 /* Note: if atom were to contain e.g. captures, we would need to
91059 * re-match the atom to get correct captures. Simply quantifiers
91060 * do not allow captures in their atom now, so this is not an issue.
91061 */
91062
91063 DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
91064 (long) atomlen));
91065 sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
91066 q--;
91067 }
91068 goto fail;
91069 }
91070 case DUK_REOP_SAVE: {
91071 duk_uint32_t idx;
91072 const duk_uint8_t *old;
91073 const duk_uint8_t *sub_sp;
91074
91075 idx = duk__bc_get_u32(re_ctx, &pc);
91076 if (idx >= re_ctx->nsaved) {
91077 /* idx is unsigned, < 0 check is not necessary */
91078 DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
91079 goto internal_error;
91080 }
91081 old = re_ctx->saved[idx];
91082 re_ctx->saved[idx] = sp;
91083 sub_sp = duk__match_regexp(re_ctx, pc, sp);
91084 if (sub_sp) {
91085 sp = sub_sp;
91086 goto match;
91087 }
91088 re_ctx->saved[idx] = old;
91089 goto fail;
91090 }
91091 case DUK_REOP_WIPERANGE: {
91092 /* Wipe capture range and save old values for backtracking.
91093 *
91094 * XXX: this typically happens with a relatively small idx_count.
91095 * It might be useful to handle cases where the count is small
91096 * (say <= 8) by saving the values in stack instead. This would
91097 * reduce memory churn and improve performance, at the cost of a
91098 * slightly higher code footprint.
91099 */
91100 duk_uint32_t idx_start, idx_count;
91101#if defined(DUK_USE_EXPLICIT_NULL_INIT)
91102 duk_uint32_t idx_end, idx;
91103#endif
91104 duk_uint8_t **range_save;
91105 const duk_uint8_t *sub_sp;
91106
91107 idx_start = duk__bc_get_u32(re_ctx, &pc);
91108 idx_count = duk__bc_get_u32(re_ctx, &pc);
91109 DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
91110 (long) idx_start, (long) idx_count,
91111 (long) idx_start, (long) (idx_start + idx_count - 1),
91112 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
91113 if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
91114 /* idx is unsigned, < 0 check is not necessary */
91115 DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
91116 (long) idx_start, (long) idx_count));
91117 goto internal_error;
91118 }
91119 DUK_ASSERT(idx_count > 0);
91120
91121 duk_require_stack(re_ctx->thr, 1);
91122 range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
91123 sizeof(duk_uint8_t *) * idx_count);
91124 DUK_ASSERT(range_save != NULL);
91125 duk_memcpy(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
91126#if defined(DUK_USE_EXPLICIT_NULL_INIT)
91127 idx_end = idx_start + idx_count;
91128 for (idx = idx_start; idx < idx_end; idx++) {
91129 re_ctx->saved[idx] = NULL;
91130 }
91131#else
91132 duk_memzero((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
91133#endif
91134
91135 sub_sp = duk__match_regexp(re_ctx, pc, sp);
91136 if (sub_sp) {
91137 /* match: keep wiped/resaved values */
91138 DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
91139 (long) idx_start, (long) (idx_start + idx_count - 1),
91140 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
91141 duk_pop_unsafe(re_ctx->thr);
91142 sp = sub_sp;
91143 goto match;
91144 }
91145
91146 /* fail: restore saves */
91147 DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
91148 (long) idx_start, (long) (idx_start + idx_count - 1),
91149 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
91150 duk_memcpy((void *) (re_ctx->saved + idx_start),
91151 (const void *) range_save,
91152 sizeof(duk_uint8_t *) * idx_count);
91153 duk_pop_unsafe(re_ctx->thr);
91154 goto fail;
91155 }
91156 case DUK_REOP_LOOKPOS:
91157 case DUK_REOP_LOOKNEG: {
91158 /*
91159 * Needs a save of multiple saved[] entries depending on what range
91160 * may be overwritten. Because the regexp parser does no such analysis,
91161 * we currently save the entire saved array here. Lookaheads are thus
91162 * a bit expensive. Note that the saved array is not needed for just
91163 * the lookahead sub-match, but for the matching of the entire sequel.
91164 *
91165 * The temporary save buffer is pushed on to the valstack to handle
91166 * errors correctly. Each lookahead causes a C recursion and pushes
91167 * more stuff on the value stack. If the C recursion limit is less
91168 * than the value stack slack, there is no need to check the stack.
91169 * We do so regardless, just in case.
91170 */
91171
91172 duk_int32_t skip;
91173 duk_uint8_t **full_save;
91174 const duk_uint8_t *sub_sp;
91175
91176 DUK_ASSERT(re_ctx->nsaved > 0);
91177
91178 duk_require_stack(re_ctx->thr, 1);
91179 full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
91180 sizeof(duk_uint8_t *) * re_ctx->nsaved);
91181 DUK_ASSERT(full_save != NULL);
91182 duk_memcpy(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
91183
91184 skip = duk__bc_get_i32(re_ctx, &pc);
91185 sub_sp = duk__match_regexp(re_ctx, pc, sp);
91186 if (op == DUK_REOP_LOOKPOS) {
91187 if (!sub_sp) {
91188 goto lookahead_fail;
91189 }
91190 } else {
91191 if (sub_sp) {
91192 goto lookahead_fail;
91193 }
91194 }
91195 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
91196 if (sub_sp) {
91197 /* match: keep saves */
91198 duk_pop_unsafe(re_ctx->thr);
91199 sp = sub_sp;
91200 goto match;
91201 }
91202
91203 /* fall through */
91204
91205 lookahead_fail:
91206 /* fail: restore saves */
91207 duk_memcpy((void *) re_ctx->saved,
91208 (const void *) full_save,
91209 sizeof(duk_uint8_t *) * re_ctx->nsaved);
91210 duk_pop_unsafe(re_ctx->thr);
91211 goto fail;
91212 }
91213 case DUK_REOP_BACKREFERENCE: {
91214 /*
91215 * Byte matching for back-references would be OK in case-
91216 * sensitive matching. In case-insensitive matching we need
91217 * to canonicalize characters, so back-reference matching needs
91218 * to be done with codepoints instead. So, we just decode
91219 * everything normally here, too.
91220 *
91221 * Note: back-reference index which is 0 or higher than
91222 * NCapturingParens (= number of capturing parens in the
91223 * -entire- regexp) is a compile time error. However, a
91224 * backreference referring to a valid capture which has
91225 * not matched anything always succeeds! See E5 Section
91226 * 15.10.2.9, step 5, sub-step 3.
91227 */
91228 duk_uint32_t idx;
91229 const duk_uint8_t *p;
91230
91231 idx = duk__bc_get_u32(re_ctx, &pc);
91232 idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */
91233 if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
91234 /* regexp compiler should catch these */
91235 DUK_D(DUK_DPRINT("internal error, backreference index insane"));
91236 goto internal_error;
91237 }
91238 if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
91239 /* capture is 'undefined', always matches! */
91240 DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
91241 (long) idx, (long) (idx + 1)));
91242 break;
91243 }
91244 DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
91245
91246 p = re_ctx->saved[idx];
91247 while (p < re_ctx->saved[idx+1]) {
91248 duk_codepoint_t c1, c2;
91249
91250 /* Note: not necessary to check p against re_ctx->input_end:
91251 * the memory access is checked by duk__inp_get_cp(), while
91252 * valid compiled regexps cannot write a saved[] entry
91253 * which points to outside the string.
91254 */
91255 c1 = duk__inp_get_cp(re_ctx, &p);
91256 DUK_ASSERT(c1 >= 0);
91257 c2 = duk__inp_get_cp(re_ctx, &sp);
91258 /* No need for an explicit c2 < 0 check: because c1 >= 0,
91259 * the comparison will always fail if c2 < 0.
91260 */
91261#if 0
91262 if (c2 < 0) {
91263 goto fail;
91264 }
91265#endif
91266 if (c1 != c2) {
91267 goto fail;
91268 }
91269 }
91270 break;
91271 }
91272 default: {
91273 DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
91274 goto internal_error;
91275 }
91276 }
91277 }
91278
91279 match:
91280 re_ctx->recursion_depth--;
91281 return sp;
91282
91283 fail:
91284 re_ctx->recursion_depth--;
91285 return NULL;
91286
91287 internal_error:
91288 DUK_ERROR_INTERNAL(re_ctx->thr);
91289 DUK_WO_NORETURN(return NULL;);
91290}
91291
91292/*
91293 * Exposed matcher function which provides the semantics of RegExp.prototype.exec().
91294 *
91295 * RegExp.prototype.test() has the same semantics as exec() but does not return the
91296 * result object (which contains the matching string and capture groups). Currently
91297 * there is no separate test() helper, so a temporary result object is created and
91298 * discarded if test() is needed. This is intentional, to save code space.
91299 *
91300 * Input stack: [ ... re_obj input ]
91301 * Output stack: [ ... result ]
91302 */
91303
91304DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
91305 duk_re_matcher_ctx re_ctx;
91306 duk_hobject *h_regexp;
91307 duk_hstring *h_bytecode;
91308 duk_hstring *h_input;
91309 duk_uint8_t *p_buf;
91310 const duk_uint8_t *pc;
91311 const duk_uint8_t *sp;
91312 duk_small_int_t match = 0;
91313 duk_small_int_t global;
91314 duk_uint_fast32_t i;
91315 double d;
91316 duk_uint32_t char_offset;
91317
91318 DUK_ASSERT(thr != NULL);
91319
91320 DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
91321 (duk_tval *) duk_get_tval(thr, -2),
91322 (duk_tval *) duk_get_tval(thr, -1)));
91323
91324 /*
91325 * Regexp instance check, bytecode check, input coercion.
91326 *
91327 * See E5 Section 15.10.6.
91328 */
91329
91330 /* TypeError if wrong; class check, see E5 Section 15.10.6 */
91331 h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP);
91332 DUK_ASSERT(h_regexp != NULL);
91333 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
91334 DUK_UNREF(h_regexp);
91335
91336 h_input = duk_to_hstring(thr, -1);
91337 DUK_ASSERT(h_input != NULL);
91338
91339 duk_xget_owndataprop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
91340 h_bytecode = duk_require_hstring(thr, -1); /* no regexp instance should exist without a non-configurable bytecode property */
91341 DUK_ASSERT(h_bytecode != NULL);
91342
91343 /*
91344 * Basic context initialization.
91345 *
91346 * Some init values are read from the bytecode header
91347 * whose format is (UTF-8 codepoints):
91348 *
91349 * uint flags
91350 * uint nsaved (even, 2n+2 where n = num captures)
91351 */
91352
91353 /* [ ... re_obj input bc ] */
91354
91355 duk_memzero(&re_ctx, sizeof(re_ctx));
91356
91357 re_ctx.thr = thr;
91358 re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
91359 re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
91360 re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
91361 re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
91362 re_ctx.saved = NULL;
91363 re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
91364 re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
91365
91366 /* read header */
91367 pc = re_ctx.bytecode;
91368 re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
91369 re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
91370 re_ctx.bytecode = pc;
91371
91372 DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
91373 global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
91374
91375 DUK_ASSERT(re_ctx.nsaved >= 2);
91376 DUK_ASSERT((re_ctx.nsaved % 2) == 0);
91377
91378 p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */
91379 DUK_UNREF(p_buf);
91380 re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL);
91381 DUK_ASSERT(re_ctx.saved != NULL);
91382
91383 /* [ ... re_obj input bc saved_buf ] */
91384
91385#if defined(DUK_USE_EXPLICIT_NULL_INIT)
91386 for (i = 0; i < re_ctx.nsaved; i++) {
91387 re_ctx.saved[i] = (duk_uint8_t *) NULL;
91388 }
91389#elif defined(DUK_USE_ZERO_BUFFER_DATA)
91390 /* buffer is automatically zeroed */
91391#else
91392 duk_memzero((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
91393#endif
91394
91395 DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
91396 (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
91397 (long) re_ctx.steps_limit));
91398
91399 /*
91400 * Get starting character offset for match, and initialize 'sp' based on it.
91401 *
91402 * Note: lastIndex is non-configurable so it must be present (we check the
91403 * internal class of the object above, so we know it is). User code can set
91404 * its value to an arbitrary (garbage) value though; E5 requires that lastIndex
91405 * be coerced to a number before using. The code below works even if the
91406 * property is missing: the value will then be coerced to zero.
91407 *
91408 * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
91409 * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset
91410 * as an integer, but pre-check it to be inside the 32-bit range before the loop.
91411 * If not, the check in E5 Section 15.10.6.2, step 9.a applies.
91412 */
91413
91414 /* XXX: lastIndex handling produces a lot of asm */
91415
91416 /* [ ... re_obj input bc saved_buf ] */
91417
91418 duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
91419 (void) duk_to_int(thr, -1); /* ToInteger(lastIndex) */
91420 d = duk_get_number(thr, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
91421 duk_pop_nodecref_unsafe(thr);
91422
91423 if (global) {
91424 if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
91425 /* match fail */
91426 char_offset = 0; /* not really necessary */
91427 DUK_ASSERT(match == 0);
91428 goto match_over;
91429 }
91430 char_offset = (duk_uint32_t) d;
91431 } else {
91432 /* lastIndex must be ignored for non-global regexps, but get the
91433 * value for (theoretical) side effects. No side effects can
91434 * really occur, because lastIndex is a normal property and is
91435 * always non-configurable for RegExp instances.
91436 */
91437 char_offset = (duk_uint32_t) 0;
91438 }
91439
91440 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
91441 sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
91442
91443 /*
91444 * Match loop.
91445 *
91446 * Try matching at different offsets until match found or input exhausted.
91447 */
91448
91449 /* [ ... re_obj input bc saved_buf ] */
91450
91451 DUK_ASSERT(match == 0);
91452
91453 for (;;) {
91454 /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
91455 DUK_ASSERT_DISABLE(char_offset >= 0);
91456 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
91457
91458 /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */
91459 DUK_ASSERT(re_ctx.recursion_depth == 0);
91460
91461 DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
91462 (long) char_offset, (const void *) sp,
91463 (const void *) re_ctx.input, (const void *) re_ctx.input_end));
91464
91465 /*
91466 * Note:
91467 *
91468 * - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
91469 * conditions; a longjmp() will terminate the entire matching process.
91470 *
91471 * - Clearing saved[] is not necessary because backtracking does it
91472 *
91473 * - Backtracking also rewinds re_ctx.recursion back to zero, unless an
91474 * internal/limit error occurs (which causes a longjmp())
91475 *
91476 * - If we supported anchored matches, we would break out here
91477 * unconditionally; however, ECMAScript regexps don't have anchored
91478 * matches. It might make sense to implement a fast bail-out if
91479 * the regexp begins with '^' and sp is not 0: currently we'll just
91480 * run through the entire input string, trivially failing the match
91481 * at every non-zero offset.
91482 */
91483
91484 if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
91485 DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
91486 match = 1;
91487 break;
91488 }
91489
91490 /* advance by one character (code point) and one char_offset */
91491 char_offset++;
91492 if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
91493 /*
91494 * Note:
91495 *
91496 * - Intentionally attempt (empty) match at char_offset == k_input->clen
91497 *
91498 * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
91499 * -> no need or use for a negative check
91500 */
91501
91502 DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
91503 break;
91504 }
91505
91506 /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
91507 (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
91508 }
91509
91510 match_over:
91511
91512 /*
91513 * Matching complete, create result array or return a 'null'. Update lastIndex
91514 * if necessary. See E5 Section 15.10.6.2.
91515 *
91516 * Because lastIndex is a character (not byte) offset, we need the character
91517 * length of the match which we conveniently get as a side effect of interning
91518 * the matching substring (0th index of result array).
91519 *
91520 * saved[0] start pointer (~ byte offset) of current match
91521 * saved[1] end pointer (~ byte offset) of current match (exclusive)
91522 * char_offset start character offset of current match (-> .index of result)
91523 * char_end_offset end character offset (computed below)
91524 */
91525
91526 /* [ ... re_obj input bc saved_buf ] */
91527
91528 if (match) {
91529#if defined(DUK_USE_ASSERTIONS)
91530 duk_hobject *h_res;
91531#endif
91532 duk_uint32_t char_end_offset = 0;
91533
91534 DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
91535
91536 DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */
91537 DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */
91538
91539 /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
91540 * advantage of now. The array is not compacted either, as regexp match
91541 * objects are usually short lived.
91542 */
91543
91544 duk_push_array(thr);
91545
91546#if defined(DUK_USE_ASSERTIONS)
91547 h_res = duk_require_hobject(thr, -1);
91548 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
91549 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
91550 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
91551#endif
91552
91553 /* [ ... re_obj input bc saved_buf res_obj ] */
91554
91555 duk_push_u32(thr, char_offset);
91556 duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX);
91557
91558 duk_dup_m4(thr);
91559 duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT);
91560
91561 for (i = 0; i < re_ctx.nsaved; i += 2) {
91562 /* Captures which are undefined have NULL pointers and are returned
91563 * as 'undefined'. The same is done when saved[] pointers are insane
91564 * (this should, of course, never happen in practice).
91565 */
91566 duk_push_uarridx(thr, (duk_uarridx_t) (i / 2));
91567
91568 if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
91569 duk_push_lstring(thr,
91570 (const char *) re_ctx.saved[i],
91571 (duk_size_t) (re_ctx.saved[i + 1] - re_ctx.saved[i]));
91572 if (i == 0) {
91573 /* Assumes that saved[0] and saved[1] are always
91574 * set by regexp bytecode (if not, char_end_offset
91575 * will be zero). Also assumes clen reflects the
91576 * correct char length.
91577 */
91578 char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1); /* add charlen */
91579 }
91580 } else {
91581 duk_push_undefined(thr);
91582 }
91583
91584 /* [ ... re_obj input bc saved_buf res_obj idx val ] */
91585 duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC);
91586 }
91587
91588 /* [ ... re_obj input bc saved_buf res_obj ] */
91589
91590 /* NB: 'length' property is automatically updated by the array setup loop */
91591
91592 if (global) {
91593 /* global regexp: lastIndex updated on match */
91594 duk_push_u32(thr, char_end_offset);
91595 duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
91596 } else {
91597 /* non-global regexp: lastIndex never updated on match */
91598 ;
91599 }
91600 } else {
91601 /*
91602 * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
91603 * of 'global' flag of the RegExp. In particular, if lastIndex is invalid
91604 * initially, it is reset to zero.
91605 */
91606
91607 DUK_DDD(DUK_DDDPRINT("regexp does not match"));
91608
91609 duk_push_null(thr);
91610
91611 /* [ ... re_obj input bc saved_buf res_obj ] */
91612
91613 duk_push_int(thr, 0);
91614 duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
91615 }
91616
91617 /* [ ... re_obj input bc saved_buf res_obj ] */
91618
91619 duk_insert(thr, -5);
91620
91621 /* [ ... res_obj re_obj input bc saved_buf ] */
91622
91623 duk_pop_n_unsafe(thr, 4);
91624
91625 /* [ ... res_obj ] */
91626
91627 /* XXX: these last tricks are unnecessary if the function is made
91628 * a genuine native function.
91629 */
91630}
91631
91632DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
91633 duk__regexp_match_helper(thr, 0 /*force_global*/);
91634}
91635
91636/* This variant is needed by String.prototype.split(); it needs to perform
91637 * global-style matching on a cloned RegExp which is potentially non-global.
91638 */
91639DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
91640 duk__regexp_match_helper(thr, 1 /*force_global*/);
91641}
91642
91643#else /* DUK_USE_REGEXP_SUPPORT */
91644
91645/* regexp support disabled */
91646
91647#endif /* DUK_USE_REGEXP_SUPPORT */
91648#line 1 "duk_selftest.c"
91649/*
91650 * Self tests to ensure execution environment is sane. Intended to catch
91651 * compiler/platform problems which cannot be detected at compile time.
91652 */
91653
91654/* #include duk_internal.h -> already included */
91655
91656#if defined(DUK_USE_SELF_TESTS)
91657
91658/*
91659 * Unions and structs for self tests
91660 */
91661
91662typedef union {
91663 double d;
91664 duk_uint8_t x[8];
91665} duk__test_double_union;
91666
91667/* Self test failed. Expects a local variable 'error_count' to exist. */
91668#define DUK__FAILED(msg) do { \
91669 DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \
91670 error_count++; \
91671 } while (0)
91672
91673#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
91674 if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
91675 DUK__FAILED("double union compares false (expected true)"); \
91676 } \
91677 } while (0)
91678
91679#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
91680 if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
91681 DUK__FAILED("double union compares true (expected false)"); \
91682 } \
91683 } while (0)
91684
91685typedef union {
91686 duk_uint32_t i;
91687 duk_uint8_t x[8];
91688} duk__test_u32_union;
91689
91690#if defined(DUK_USE_INTEGER_LE)
91691#define DUK__U32_INIT(u, a, b, c, d) do { \
91692 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
91693 } while (0)
91694#elif defined(DUK_USE_INTEGER_ME)
91695#error integer mixed endian not supported now
91696#elif defined(DUK_USE_INTEGER_BE)
91697#define DUK__U32_INIT(u, a, b, c, d) do { \
91698 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
91699 } while (0)
91700#else
91701#error unknown integer endianness
91702#endif
91703
91704#if defined(DUK_USE_DOUBLE_LE)
91705#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
91706 (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \
91707 (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \
91708 } while (0)
91709#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
91710 ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \
91711 (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a))
91712#elif defined(DUK_USE_DOUBLE_ME)
91713#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
91714 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
91715 (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \
91716 } while (0)
91717#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
91718 ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \
91719 (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e))
91720#elif defined(DUK_USE_DOUBLE_BE)
91721#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
91722 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
91723 (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \
91724 } while (0)
91725#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
91726 ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \
91727 (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h))
91728#else
91729#error unknown double endianness
91730#endif
91731
91732/*
91733 * Various sanity checks for typing
91734 */
91735
91736DUK_LOCAL duk_uint_t duk__selftest_types(void) {
91737 duk_uint_t error_count = 0;
91738
91739 if (!(sizeof(duk_int8_t) == 1 &&
91740 sizeof(duk_uint8_t) == 1 &&
91741 sizeof(duk_int16_t) == 2 &&
91742 sizeof(duk_uint16_t) == 2 &&
91743 sizeof(duk_int32_t) == 4 &&
91744 sizeof(duk_uint32_t) == 4)) {
91745 DUK__FAILED("duk_(u)int{8,16,32}_t size");
91746 }
91747#if defined(DUK_USE_64BIT_OPS)
91748 if (!(sizeof(duk_int64_t) == 8 &&
91749 sizeof(duk_uint64_t) == 8)) {
91750 DUK__FAILED("duk_(u)int64_t size");
91751 }
91752#endif
91753
91754 if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
91755 /* Some internal code now assumes that all duk_uint_t values
91756 * can be expressed with a duk_size_t.
91757 */
91758 DUK__FAILED("duk_size_t is smaller than duk_uint_t");
91759 }
91760 if (!(sizeof(duk_int_t) >= 4)) {
91761 DUK__FAILED("duk_int_t is not 32 bits");
91762 }
91763
91764 return error_count;
91765}
91766
91767/*
91768 * Packed tval sanity
91769 */
91770
91771DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) {
91772 duk_uint_t error_count = 0;
91773
91774#if defined(DUK_USE_PACKED_TVAL)
91775 if (sizeof(void *) > 4) {
91776 DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4");
91777 }
91778#endif
91779
91780 return error_count;
91781}
91782
91783/*
91784 * Two's complement arithmetic.
91785 */
91786
91787DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) {
91788 duk_uint_t error_count = 0;
91789 volatile int test;
91790 test = -1;
91791
91792 /* Note that byte order doesn't affect this test: all bytes in
91793 * 'test' will be 0xFF for two's complement.
91794 */
91795 if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
91796 DUK__FAILED("two's complement arithmetic");
91797 }
91798
91799 return error_count;
91800}
91801
91802/*
91803 * Byte order. Important to self check, because on some exotic platforms
91804 * there is no actual detection but rather assumption based on platform
91805 * defines.
91806 */
91807
91808DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) {
91809 duk_uint_t error_count = 0;
91810 duk__test_u32_union u1;
91811 duk__test_double_union u2;
91812
91813 /*
91814 * >>> struct.pack('>d', 102030405060).encode('hex')
91815 * '4237c17c6dc40000'
91816 */
91817
91818 DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef);
91819 DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00);
91820
91821 if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
91822 DUK__FAILED("duk_uint32_t byte order");
91823 }
91824
91825 if (!duk_double_equals(u2.d, 102030405060.0)) {
91826 DUK__FAILED("double byte order");
91827 }
91828
91829 return error_count;
91830}
91831
91832/*
91833 * DUK_BSWAP macros
91834 */
91835
91836DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) {
91837 duk_uint_t error_count = 0;
91838 volatile duk_uint32_t x32_input, x32_output;
91839 duk_uint32_t x32;
91840 volatile duk_uint16_t x16_input, x16_output;
91841 duk_uint16_t x16;
91842 duk_double_union du;
91843 duk_double_t du_diff;
91844#if defined(DUK_BSWAP64)
91845 volatile duk_uint64_t x64_input, x64_output;
91846 duk_uint64_t x64;
91847#endif
91848
91849 /* Cover both compile time and runtime bswap operations, as these
91850 * may have different bugs.
91851 */
91852
91853 x16_input = 0xbeefUL;
91854 x16 = x16_input;
91855 x16 = DUK_BSWAP16(x16);
91856 x16_output = x16;
91857 if (x16_output != (duk_uint16_t) 0xefbeUL) {
91858 DUK__FAILED("DUK_BSWAP16");
91859 }
91860
91861 x16 = 0xbeefUL;
91862 x16 = DUK_BSWAP16(x16);
91863 if (x16 != (duk_uint16_t) 0xefbeUL) {
91864 DUK__FAILED("DUK_BSWAP16");
91865 }
91866
91867 x32_input = 0xdeadbeefUL;
91868 x32 = x32_input;
91869 x32 = DUK_BSWAP32(x32);
91870 x32_output = x32;
91871 if (x32_output != (duk_uint32_t) 0xefbeaddeUL) {
91872 DUK__FAILED("DUK_BSWAP32");
91873 }
91874
91875 x32 = 0xdeadbeefUL;
91876 x32 = DUK_BSWAP32(x32);
91877 if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
91878 DUK__FAILED("DUK_BSWAP32");
91879 }
91880
91881#if defined(DUK_BSWAP64)
91882 x64_input = DUK_U64_CONSTANT(0x8899aabbccddeeff);
91883 x64 = x64_input;
91884 x64 = DUK_BSWAP64(x64);
91885 x64_output = x64;
91886 if (x64_output != (duk_uint64_t) DUK_U64_CONSTANT(0xffeeddccbbaa9988)) {
91887 DUK__FAILED("DUK_BSWAP64");
91888 }
91889
91890 x64 = DUK_U64_CONSTANT(0x8899aabbccddeeff);
91891 x64 = DUK_BSWAP64(x64);
91892 if (x64 != (duk_uint64_t) DUK_U64_CONSTANT(0xffeeddccbbaa9988)) {
91893 DUK__FAILED("DUK_BSWAP64");
91894 }
91895#endif
91896
91897 /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
91898 * (2.008366013071895,)
91899 */
91900
91901 du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
91902 du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
91903 DUK_DBLUNION_DOUBLE_NTOH(&du);
91904 du_diff = du.d - 2.008366013071895;
91905#if 0
91906 DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff));
91907#endif
91908 if (du_diff > 1e-15) {
91909 /* Allow very small lenience because some compilers won't parse
91910 * exact IEEE double constants (happened in matrix testing with
91911 * Linux gcc-4.8 -m32 at least).
91912 */
91913#if 0
91914 DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
91915 (unsigned int) du.uc[0], (unsigned int) du.uc[1],
91916 (unsigned int) du.uc[2], (unsigned int) du.uc[3],
91917 (unsigned int) du.uc[4], (unsigned int) du.uc[5],
91918 (unsigned int) du.uc[6], (unsigned int) du.uc[7]));
91919#endif
91920 DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH");
91921 }
91922
91923 return error_count;
91924}
91925
91926/*
91927 * Basic double / byte union memory layout.
91928 */
91929
91930DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) {
91931 duk_uint_t error_count = 0;
91932
91933 if (sizeof(duk__test_double_union) != 8) {
91934 DUK__FAILED("invalid union size");
91935 }
91936
91937 return error_count;
91938}
91939
91940/*
91941 * Union aliasing, see misc/clang_aliasing.c.
91942 */
91943
91944DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) {
91945 /* This testcase fails when Emscripten-generated code runs on Firefox.
91946 * It's not an issue because the failure should only affect packed
91947 * duk_tval representation, which is not used with Emscripten.
91948 */
91949#if defined(DUK_USE_PACKED_TVAL)
91950 duk_uint_t error_count = 0;
91951 duk__test_double_union a, b;
91952
91953 /* Test signaling NaN and alias assignment in all endianness combinations.
91954 */
91955
91956 /* little endian */
91957 a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44;
91958 a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff;
91959 b = a;
91960 DUK__DBLUNION_CMP_TRUE(&a, &b);
91961
91962 /* big endian */
91963 a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00;
91964 a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11;
91965 b = a;
91966 DUK__DBLUNION_CMP_TRUE(&a, &b);
91967
91968 /* mixed endian */
91969 a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff;
91970 a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44;
91971 b = a;
91972 DUK__DBLUNION_CMP_TRUE(&a, &b);
91973
91974 return error_count;
91975#else
91976 DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
91977 return 0;
91978#endif
91979}
91980
91981/*
91982 * Zero sign, see misc/tcc_zerosign2.c.
91983 */
91984
91985DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) {
91986 duk_uint_t error_count = 0;
91987 duk__test_double_union a, b;
91988
91989 a.d = 0.0;
91990 b.d = -a.d;
91991 DUK__DBLUNION_CMP_FALSE(&a, &b);
91992
91993 return error_count;
91994}
91995
91996/*
91997 * Rounding mode: Duktape assumes round-to-nearest, check that this is true.
91998 * If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST,
91999 * but we don't want to rely on that header; and even if we did, it's good
92000 * to ensure the rounding actually works.
92001 */
92002
92003DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) {
92004 duk_uint_t error_count = 0;
92005 duk__test_double_union a, b, c;
92006
92007#if 0
92008 /* Include <fenv.h> and test manually; these trigger failures: */
92009 fesetround(FE_UPWARD);
92010 fesetround(FE_DOWNWARD);
92011 fesetround(FE_TOWARDZERO);
92012
92013 /* This is the default and passes. */
92014 fesetround(FE_TONEAREST);
92015#endif
92016
92017 /* Rounding tests check that none of the other modes (round to
92018 * +Inf, round to -Inf, round to zero) can be active:
92019 * http://www.gnu.org/software/libc/manual/html_node/Rounding.html
92020 */
92021
92022 /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp.
92023 * Round to nearest: 1.0
92024 * Round to +Inf: 1.0 + ulp
92025 * Round to -Inf: 1.0
92026 * Round to zero: 1.0
92027 * => Correct result eliminates round to +Inf.
92028 */
92029 DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
92030 DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
92031 duk_memset((void *) &c, 0, sizeof(c));
92032 c.d = a.d + b.d;
92033 if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) {
92034 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
92035 (unsigned int) c.x[0], (unsigned int) c.x[1],
92036 (unsigned int) c.x[2], (unsigned int) c.x[3],
92037 (unsigned int) c.x[4], (unsigned int) c.x[5],
92038 (unsigned int) c.x[6], (unsigned int) c.x[7]));
92039 DUK__FAILED("invalid result from 1.0 + 0.5ulp");
92040 }
92041
92042 /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp.
92043 * Round to nearest: 1.0 + 2*ulp (round to even mantissa)
92044 * Round to +Inf: 1.0 + 2*ulp
92045 * Round to -Inf: 1.0 + ulp
92046 * Round to zero: 1.0 + ulp
92047 * => Correct result eliminates round to -Inf and round to zero.
92048 */
92049 DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
92050 DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
92051 duk_memset((void *) &c, 0, sizeof(c));
92052 c.d = a.d + b.d;
92053 if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) {
92054 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
92055 (unsigned int) c.x[0], (unsigned int) c.x[1],
92056 (unsigned int) c.x[2], (unsigned int) c.x[3],
92057 (unsigned int) c.x[4], (unsigned int) c.x[5],
92058 (unsigned int) c.x[6], (unsigned int) c.x[7]));
92059 DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp");
92060 }
92061
92062 /* Could do negative number testing too, but the tests above should
92063 * differentiate between IEEE 754 rounding modes.
92064 */
92065 return error_count;
92066}
92067
92068/*
92069 * fmod(): often a portability issue in embedded or bare platform targets.
92070 * Check for at least minimally correct behavior. Unlike some other math
92071 * functions (like cos()) Duktape relies on fmod() internally too.
92072 */
92073
92074DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
92075 duk_uint_t error_count = 0;
92076 duk__test_double_union u1, u2;
92077 volatile duk_double_t t1, t2, t3;
92078
92079 /* fmod() with integer argument and exponent 2^32 is used by e.g.
92080 * ToUint32() and some Duktape internals.
92081 */
92082 u1.d = DUK_FMOD(10.0, 4294967296.0);
92083 u2.d = 10.0;
92084 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92085
92086 u1.d = DUK_FMOD(4294967306.0, 4294967296.0);
92087 u2.d = 10.0;
92088 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92089
92090 u1.d = DUK_FMOD(73014444042.0, 4294967296.0);
92091 u2.d = 10.0;
92092 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92093
92094 /* 52-bit integer split into two parts:
92095 * >>> 0x1fedcba9876543
92096 * 8987183256397123
92097 * >>> float(0x1fedcba9876543) / float(2**53)
92098 * 0.9977777777777778
92099 */
92100 u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0);
92101 u2.d = (duk_double_t) 0xa9876543UL;
92102 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92103 t1 = 8987183256397123.0;
92104 t2 = 4294967296.0;
92105 t3 = t1 / t2;
92106 u1.d = DUK_FLOOR(t3);
92107 u2.d = (duk_double_t) 0x1fedcbUL;
92108 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92109
92110 /* C99 behavior is for fmod() result sign to mathc argument sign. */
92111 u1.d = DUK_FMOD(-10.0, 4294967296.0);
92112 u2.d = -10.0;
92113 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92114
92115 u1.d = DUK_FMOD(-4294967306.0, 4294967296.0);
92116 u2.d = -10.0;
92117 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92118
92119 u1.d = DUK_FMOD(-73014444042.0, 4294967296.0);
92120 u2.d = -10.0;
92121 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
92122
92123 return error_count;
92124}
92125
92126/*
92127 * Struct size/alignment if platform requires it
92128 *
92129 * There are some compiler specific struct padding pragmas etc in use, this
92130 * selftest ensures they're correctly detected and used.
92131 */
92132
92133DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) {
92134 duk_uint_t error_count = 0;
92135
92136#if (DUK_USE_ALIGN_BY == 4)
92137 if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
92138 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4");
92139 }
92140#elif (DUK_USE_ALIGN_BY == 8)
92141 if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
92142 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8");
92143 }
92144#elif (DUK_USE_ALIGN_BY == 1)
92145 /* no check */
92146#else
92147#error invalid DUK_USE_ALIGN_BY
92148#endif
92149 return error_count;
92150}
92151
92152/*
92153 * 64-bit arithmetic
92154 *
92155 * There are some platforms/compilers where 64-bit types are available
92156 * but don't work correctly. Test for known cases.
92157 */
92158
92159DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) {
92160 duk_uint_t error_count = 0;
92161#if defined(DUK_USE_64BIT_OPS)
92162 volatile duk_int64_t i;
92163 volatile duk_double_t d;
92164
92165 /* Catch a double-to-int64 cast issue encountered in practice. */
92166 d = 2147483648.0;
92167 i = (duk_int64_t) d;
92168 if (i != DUK_I64_CONSTANT(0x80000000)) {
92169 DUK__FAILED("casting 2147483648.0 to duk_int64_t failed");
92170 }
92171#else
92172 /* nop */
92173#endif
92174 return error_count;
92175}
92176
92177/*
92178 * Casting
92179 */
92180
92181DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) {
92182 /*
92183 * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
92184 */
92185
92186 duk_uint_t error_count = 0;
92187
92188 duk_double_t d1, d2;
92189 duk_small_uint_t u;
92190
92191 duk_double_t d1v, d2v;
92192 duk_small_uint_t uv;
92193
92194 /* Test without volatiles */
92195
92196 d1 = 1.0;
92197 u = (duk_small_uint_t) d1;
92198 d2 = (duk_double_t) u;
92199
92200 if (!(duk_double_equals(d1, 1.0) && u == 1 && duk_double_equals(d2, 1.0) && duk_double_equals(d1, d2))) {
92201 DUK__FAILED("double to duk_small_uint_t cast failed");
92202 }
92203
92204 /* Same test with volatiles */
92205
92206 d1v = 1.0;
92207 uv = (duk_small_uint_t) d1v;
92208 d2v = (duk_double_t) uv;
92209
92210 if (!(duk_double_equals(d1v, 1.0) && uv == 1 && duk_double_equals(d2v, 1.0) && duk_double_equals(d1v, d2v))) {
92211 DUK__FAILED("double to duk_small_uint_t cast failed");
92212 }
92213
92214 return error_count;
92215}
92216
92217DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) {
92218 /*
92219 * This test fails on an exotic ARM target; double-to-uint
92220 * cast is incorrectly clamped to -signed- int highest value.
92221 *
92222 * https://github.com/svaarala/duktape/issues/336
92223 */
92224
92225 duk_uint_t error_count = 0;
92226 duk_double_t dv;
92227 duk_uint32_t uv;
92228
92229 dv = 3735928559.0; /* 0xdeadbeef in decimal */
92230 uv = (duk_uint32_t) dv;
92231
92232 if (uv != 0xdeadbeefUL) {
92233 DUK__FAILED("double to duk_uint32_t cast failed");
92234 }
92235
92236 return error_count;
92237}
92238
92239/*
92240 * Minimal test of user supplied allocation functions
92241 *
92242 * - Basic alloc + realloc + free cycle
92243 *
92244 * - Realloc to significantly larger size to (hopefully) trigger a
92245 * relocation and check that relocation copying works
92246 */
92247
92248DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
92249 duk_realloc_function realloc_func,
92250 duk_free_function free_func,
92251 void *udata) {
92252 duk_uint_t error_count = 0;
92253 void *ptr;
92254 void *new_ptr;
92255 duk_small_int_t i, j;
92256 unsigned char x;
92257
92258 if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) {
92259 return 0;
92260 }
92261
92262 for (i = 1; i <= 256; i++) {
92263 ptr = alloc_func(udata, (duk_size_t) i);
92264 if (ptr == NULL) {
92265 DUK_D(DUK_DPRINT("alloc failed, ignore"));
92266 continue; /* alloc failed, ignore */
92267 }
92268 for (j = 0; j < i; j++) {
92269 ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j);
92270 }
92271 new_ptr = realloc_func(udata, ptr, 1024);
92272 if (new_ptr == NULL) {
92273 DUK_D(DUK_DPRINT("realloc failed, ignore"));
92274 free_func(udata, ptr);
92275 continue; /* realloc failed, ignore */
92276 }
92277 ptr = new_ptr;
92278 for (j = 0; j < i; j++) {
92279 x = ((unsigned char *) ptr)[j];
92280 if (x != (unsigned char) (0x80 + j)) {
92281 DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx",
92282 (long) j, (unsigned long) x));
92283 DUK__FAILED("byte compare after realloc");
92284 break;
92285 }
92286 }
92287 free_func(udata, ptr);
92288 }
92289
92290 return error_count;
92291}
92292
92293/*
92294 * Self test main
92295 */
92296
92297DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
92298 duk_realloc_function realloc_func,
92299 duk_free_function free_func,
92300 void *udata) {
92301 duk_uint_t error_count = 0;
92302
92303 DUK_D(DUK_DPRINT("self test starting"));
92304
92305 error_count += duk__selftest_types();
92306 error_count += duk__selftest_packed_tval();
92307 error_count += duk__selftest_twos_complement();
92308 error_count += duk__selftest_byte_order();
92309 error_count += duk__selftest_bswap_macros();
92310 error_count += duk__selftest_double_union_size();
92311 error_count += duk__selftest_double_aliasing();
92312 error_count += duk__selftest_double_zero_sign();
92313 error_count += duk__selftest_double_rounding();
92314 error_count += duk__selftest_fmod();
92315 error_count += duk__selftest_struct_align();
92316 error_count += duk__selftest_64bit_arithmetic();
92317 error_count += duk__selftest_cast_double_to_small_uint();
92318 error_count += duk__selftest_cast_double_to_uint32();
92319 error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata);
92320
92321 DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count));
92322
92323 return error_count;
92324}
92325
92326#endif /* DUK_USE_SELF_TESTS */
92327
92328/* automatic undefs */
92329#undef DUK__DBLUNION_CMP_FALSE
92330#undef DUK__DBLUNION_CMP_TRUE
92331#undef DUK__DOUBLE_COMPARE
92332#undef DUK__DOUBLE_INIT
92333#undef DUK__FAILED
92334#undef DUK__U32_INIT
92335/* #include duk_internal.h -> already included */
92336#line 2 "duk_tval.c"
92337
92338#if defined(DUK_USE_FASTINT)
92339
92340/*
92341 * Manually optimized double-to-fastint downgrade check.
92342 *
92343 * This check has a large impact on performance, especially for fastint
92344 * slow paths, so must be changed carefully. The code should probably be
92345 * optimized for the case where the result does not fit into a fastint,
92346 * to minimize the penalty for "slow path code" dealing with fractions etc.
92347 *
92348 * At least on one tested soft float ARM platform double-to-int64 coercion
92349 * is very slow (and sometimes produces incorrect results, see self tests).
92350 * This algorithm combines a fastint compatibility check and extracting the
92351 * integer value from an IEEE double for setting the tagged fastint. For
92352 * other platforms a more naive approach might be better.
92353 *
92354 * See doc/fastint.rst for details.
92355 */
92356
92357DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) {
92358 duk_double_union du;
92359 duk_int64_t i;
92360 duk_small_int_t expt;
92361 duk_small_int_t shift;
92362
92363 /* XXX: optimize for packed duk_tval directly? */
92364
92365 du.d = x;
92366 i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
92367 expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
92368 shift = expt - 1023;
92369
92370 if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
92371 duk_int64_t t;
92372
92373 if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) {
92374 t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */
92375 t = t & DUK_I64_CONSTANT(0x001fffffffffffff);
92376 t = t >> (52 - shift);
92377 if (i < 0) {
92378 t = -t;
92379 }
92380 DUK_TVAL_SET_FASTINT(tv, t);
92381 return;
92382 }
92383 } else if (shift == -1023) { /* exponent 0 */
92384 if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
92385 /* Note: reject negative zero. */
92386 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
92387 return;
92388 }
92389 } else if (shift == 47) { /* exponent 1070 */
92390 if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
92391 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
92392 return;
92393 }
92394 }
92395
92396 DUK_TVAL_SET_DOUBLE(tv, x);
92397 return;
92398}
92399
92400DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) {
92401 duk_tval_set_number_chkfast_fast(tv, x);
92402}
92403
92404/*
92405 * Manually optimized number-to-double conversion
92406 */
92407
92408#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
92409DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
92410 duk_double_union du;
92411 duk_uint64_t t;
92412
92413 t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
92414 if ((t >> 48) != DUK_TAG_FASTINT) {
92415 return tv->d;
92416 } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) {
92417 t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
92418 t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */
92419 t |= DUK_U64_CONSTANT(0xc330000000000000);
92420 DUK_DBLUNION_SET_UINT64(&du, t);
92421 return du.d + 4503599627370496.0; /* 1 << 52 */
92422 } else if (t != 0) {
92423 t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */
92424 t |= DUK_U64_CONSTANT(0x4330000000000000);
92425 DUK_DBLUNION_SET_UINT64(&du, t);
92426 return du.d - 4503599627370496.0; /* 1 << 52 */
92427 } else {
92428 return 0.0; /* zero */
92429 }
92430}
92431#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
92432
92433#if 0 /* unused */
92434#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
92435DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
92436 duk_double_union du;
92437 duk_uint64_t t;
92438
92439 DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
92440
92441 if (tv->t == DUK_TAG_FASTINT) {
92442 if (tv->v.fi >= 0) {
92443 t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
92444 DUK_DBLUNION_SET_UINT64(&du, t);
92445 return du.d - 4503599627370496.0; /* 1 << 52 */
92446 } else {
92447 t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
92448 DUK_DBLUNION_SET_UINT64(&du, t);
92449 return du.d + 4503599627370496.0; /* 1 << 52 */
92450 }
92451 } else {
92452 return tv->v.d;
92453 }
92454}
92455#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
92456#endif /* 0 */
92457
92458#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
92459DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
92460 duk_double_union du;
92461 duk_uint64_t t;
92462
92463 DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
92464
92465 if (tv->v.fi >= 0) {
92466 t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
92467 DUK_DBLUNION_SET_UINT64(&du, t);
92468 return du.d - 4503599627370496.0; /* 1 << 52 */
92469 } else {
92470 t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
92471 DUK_DBLUNION_SET_UINT64(&du, t);
92472 return du.d + 4503599627370496.0; /* 1 << 52 */
92473 }
92474}
92475#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
92476
92477#endif /* DUK_USE_FASTINT */
92478
92479/*
92480 * Assertion helpers.
92481 */
92482
92483#if defined(DUK_USE_ASSERTIONS)
92484DUK_INTERNAL void duk_tval_assert_valid(duk_tval *tv) {
92485 DUK_ASSERT(tv != NULL);
92486}
92487#endif
92488#line 1 "duk_unicode_tables.c"
92489/*
92490 * Unicode support tables automatically generated during build.
92491 */
92492
92493/* #include duk_internal.h -> already included */
92494
92495/*
92496 * Unicode tables containing ranges of Unicode characters in a
92497 * packed format. These tables are used to match non-ASCII
92498 * characters of complex productions by resorting to a linear
92499 * range-by-range comparison. This is very slow, but is expected
92500 * to be very rare in practical ECMAScript source code, and thus
92501 * compactness is most important.
92502 *
92503 * The tables are matched using uni_range_match() and the format
92504 * is described in tools/extract_chars.py.
92505 */
92506
92507#if defined(DUK_USE_SOURCE_NONBMP)
92508/* IdentifierStart production with ASCII excluded */
92509/* duk_unicode_ids_noa[] */
92510/*
92511 * Automatically generated by extract_chars.py, do not edit!
92512 */
92513
92514const duk_uint8_t duk_unicode_ids_noa[1116] = {
92515249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
925162,240,66,244,50,247,185,249,98,241,99,7,241,159,57,240,181,63,31,241,191,
9251721,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
92518101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115,
9251919,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5,
9252047,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,
9252118,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,
9252212,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,
925236,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,2,66,240,130,
925242,146,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,
9252524,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,63,17,35,
9252654,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,240,18,240,
92527166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,
92528152,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,240,122,
92529242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,43,241,67,
92530136,241,179,47,27,50,82,20,6,251,15,50,255,224,8,53,63,22,53,55,32,32,32,
9253147,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,
9253268,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,
9253352,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,
9253412,146,240,184,132,52,95,70,114,47,74,35,111,27,47,78,240,63,11,242,127,0,
92535255,224,244,255,240,0,138,143,60,255,240,4,14,47,2,255,227,127,243,95,30,
9253663,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,37,52,242,42,
9253734,35,47,7,240,255,36,240,15,34,243,5,64,33,207,12,191,7,240,191,13,143,31,
92538240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
92539240,162,58,130,213,53,53,166,38,47,27,43,159,99,240,255,255,0,26,150,223,7,
9254095,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
92541207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
92542207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255,
92543223,13,79,33,242,31,16,239,14,111,22,191,14,63,20,87,36,241,207,142,240,79,
9254420,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20,3,
92545240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15,1,
9254650,34,240,223,28,240,212,240,223,21,114,240,207,13,242,107,240,107,240,62,
92547240,47,96,243,159,41,242,62,242,62,241,79,254,13,15,13,176,159,6,248,207,7,
92548223,37,243,223,29,241,47,9,240,207,20,240,240,207,19,64,223,32,240,3,240,
92549112,32,241,95,2,47,9,244,102,32,35,46,41,143,31,241,135,49,63,6,38,33,36,
9255064,240,64,212,249,15,37,240,67,240,96,241,47,32,240,97,32,250,175,31,241,
92551179,241,111,32,240,96,242,223,27,224,243,159,11,253,127,28,246,111,48,241,
9255216,249,39,63,23,240,32,32,240,224,191,24,128,240,112,207,30,240,80,241,79,
9255341,255,152,47,21,240,48,242,63,14,246,38,33,47,22,240,112,240,181,33,47,16,
92554240,0,255,224,59,240,63,254,0,31,254,40,207,88,245,255,3,251,79,254,155,15,
92555254,50,31,254,236,95,254,19,159,255,0,16,173,255,225,43,143,15,246,63,14,
92556240,79,32,240,35,241,31,5,111,3,255,225,164,243,15,114,243,182,15,52,207,
9255750,18,15,14,255,240,0,110,169,255,225,229,255,240,1,64,31,254,1,31,35,47,3,
9255857,255,224,126,255,231,248,245,182,196,136,159,255,0,6,90,244,82,243,114,
9255919,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,255,224,70,63,9,47,
925609,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,232,40,241,219,111,2,
9256115,254,6,95,28,255,228,8,251,95,45,243,72,15,254,58,131,47,11,33,32,48,41,
9256235,32,32,112,80,32,32,34,33,32,48,32,32,32,32,33,32,51,38,35,35,32,41,47,1,
9256398,36,47,1,255,240,0,3,143,255,0,149,201,241,191,254,242,124,252,227,255,
92564240,0,87,79,0,255,240,0,194,63,254,177,63,254,17,0,
92565};
92566#else
92567/* IdentifierStart production with ASCII and non-BMP excluded */
92568/* duk_unicode_ids_noabmp[] */
92569/*
92570 * Automatically generated by extract_chars.py, do not edit!
92571 */
92572
92573const duk_uint8_t duk_unicode_ids_noabmp[625] = {
92574249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
925752,240,66,244,50,247,185,249,98,241,99,7,241,159,57,240,181,63,31,241,191,
9257621,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
92577101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115,
9257819,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5,
9257947,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,
9258018,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,
9258112,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,
925826,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,2,66,240,130,
925832,146,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,
9258424,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,63,17,35,
9258554,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,240,18,240,
92586166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,
92587152,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,240,122,
92588242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,43,241,67,
92589136,241,179,47,27,50,82,20,6,251,15,50,255,224,8,53,63,22,53,55,32,32,32,
9259047,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,
9259168,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,
9259252,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,
9259312,146,240,184,132,52,95,70,114,47,74,35,111,27,47,78,240,63,11,242,127,0,
92594255,224,244,255,240,0,138,143,60,255,240,4,14,47,2,255,227,127,243,95,30,
9259563,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,37,52,242,42,
9259634,35,47,7,240,255,36,240,15,34,243,5,64,33,207,12,191,7,240,191,13,143,31,
92597240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
92598240,162,58,130,213,53,53,166,38,47,27,43,159,99,240,255,255,0,26,150,223,7,
9259995,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
92600207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
92601207,73,69,53,53,50,0,
92602};
92603#endif
92604
92605#if defined(DUK_USE_SOURCE_NONBMP)
92606/* IdentifierStart production with Letter and ASCII excluded */
92607/* duk_unicode_ids_m_let_noa[] */
92608/*
92609 * Automatically generated by extract_chars.py, do not edit!
92610 */
92611
92612const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
92613255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
92614249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240,
92615};
92616#else
92617/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
92618/* duk_unicode_ids_m_let_noabmp[] */
92619/*
92620 * Automatically generated by extract_chars.py, do not edit!
92621 */
92622
92623const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
92624255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
92625249,0,
92626};
92627#endif
92628
92629#if defined(DUK_USE_SOURCE_NONBMP)
92630/* IdentifierPart production with IdentifierStart and ASCII excluded */
92631/* duk_unicode_idp_m_ids_noa[] */
92632/*
92633 * Automatically generated by extract_chars.py, do not edit!
92634 */
92635
92636const duk_uint8_t duk_unicode_idp_m_ids_noa[576] = {
92637255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
92638245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,160,240,163,40,
9263934,36,241,210,246,158,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
92640160,177,57,240,0,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,
92641240,97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,
926429,240,36,242,182,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,
9264335,242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,
92644215,41,244,144,56,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,
92645245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,
92646241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,
92647242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,
9264857,241,237,242,47,4,153,121,246,130,47,5,80,112,50,251,143,42,36,255,225,0,
9264931,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,
9265031,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,
92651242,79,2,185,127,2,234,240,231,240,188,241,227,242,29,240,25,192,185,242,
9265229,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
92653225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64,
92654248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,225,49,57,
92655159,254,16,10,250,18,242,126,241,25,240,19,241,250,242,121,114,241,109,41,
9265697,241,224,210,242,45,147,73,244,75,112,249,43,105,115,242,145,38,49,50,
92657160,177,54,68,251,47,2,169,80,244,63,4,217,252,118,56,240,209,244,79,1,240,
9265825,244,60,153,244,94,89,254,78,249,121,253,150,54,64,240,233,241,166,35,
92659144,170,242,15,0,255,224,137,114,127,2,159,42,240,98,223,108,84,2,18,98,9,
92660159,34,66,18,73,159,254,3,211,255,240,3,165,217,247,132,242,214,240,185,
92661255,226,233,2,242,120,63,255,0,59,254,31,255,0,3,186,68,89,115,111,16,63,
92662134,47,254,71,223,34,255,224,244,242,117,242,41,15,0,15,8,66,239,254,68,70,
9266347,1,54,33,36,255,118,169,255,224,150,223,254,76,166,245,246,105,255,240,
92664192,105,175,224,0,
92665};
92666#else
92667/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
92668/* duk_unicode_idp_m_ids_noabmp[] */
92669/*
92670 * Automatically generated by extract_chars.py, do not edit!
92671 */
92672
92673const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358] = {
92674255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
92675245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,160,240,163,40,
9267634,36,241,210,246,158,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
92677160,177,57,240,0,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,
92678240,97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,
926799,240,36,242,182,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,
9268035,242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,
92681215,41,244,144,56,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,
92682245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,
92683241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,
92684242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,
9268557,241,237,242,47,4,153,121,246,130,47,5,80,112,50,251,143,42,36,255,225,0,
9268631,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,
9268731,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,
92688242,79,2,185,127,2,234,240,231,240,188,241,227,242,29,240,25,192,185,242,
9268929,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
92690225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0,
92691};
92692#endif
92693
92694/*
92695 * Case conversion tables generated using tools/extract_caseconv.py.
92696 */
92697
92698/* duk_unicode_caseconv_uc[] */
92699/* duk_unicode_caseconv_lc[] */
92700
92701/*
92702 * Automatically generated by extract_caseconv.py, do not edit!
92703 */
92704
92705const duk_uint8_t duk_unicode_caseconv_uc[1411] = {
92706152,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
92707128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
92708104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,8,104,14,72,43,16,253,
9270928,189,6,39,240,39,224,24,114,12,16,132,16,248,0,248,64,129,241,1,241,128,
92710195,228,3,229,2,7,204,7,206,4,15,160,15,164,6,31,96,31,104,16,62,224,63,
92711116,8,125,200,127,32,32,251,176,254,208,33,247,129,255,128,67,239,67,253,
9271264,135,223,7,254,129,15,216,15,220,2,31,208,31,216,4,63,192,63,208,8,133,
92713192,133,128,129,38,129,37,177,162,195,2,192,5,229,160,2,20,9,170,220,4,232,
9271440,127,160,255,144,154,136,4,4,4,0,192,9,152,9,144,48,19,160,19,145,0,41,
9271596,41,69,192,94,128,94,65,128,193,128,193,2,1,161,1,160,6,3,104,3,102,8,7,
9271656,7,52,64,14,248,14,240,144,31,144,31,130,128,68,96,68,66,64,145,192,145,
92717130,129,184,129,184,2,3,217,3,216,24,8,194,8,192,68,18,44,18,40,216,38,16,
9271838,8,112,77,16,77,6,3,192,35,192,18,199,168,71,168,24,15,168,143,172,132,
9271944,104,44,103,6,89,2,89,0,200,179,176,179,172,21,50,13,50,1,122,104,26,104,
927201,212,228,116,228,65,233,204,233,204,143,211,189,83,188,130,167,127,167,
92721126,11,79,35,79,32,10,158,94,158,88,85,61,173,61,160,97,192,107,64,107,1,0,
92722226,128,226,3,1,198,1,196,6,3,228,3,226,8,10,0,6,152,16,31,192,31,184,34,
92723199,50,199,32,65,128,196,0,195,130,1,185,1,184,4,4,205,79,84,8,0,192,143,0,
92724142,193,1,52,128,203,2,45,39,16,199,5,253,0,11,80,57,192,15,240,23,128,19,
9272516,4,144,23,240,5,48,24,0,36,48,25,32,25,16,25,80,31,96,25,144,25,128,25,
92726160,35,208,25,224,34,0,26,128,26,112,27,240,31,112,29,208,24,224,31,48,31,
9272716,37,2,198,240,37,18,198,208,37,34,199,0,37,48,24,16,37,64,24,96,37,144,
9272824,240,37,176,25,0,37,202,122,176,38,0,25,48,38,26,122,192,38,48,25,64,38,
9272990,120,208,38,128,25,112,38,178,198,32,38,202,122,208,39,18,198,224,39,32,
9273025,208,39,80,25,240,39,210,198,64,40,42,124,80,40,122,123,16,40,128,26,224,
9273140,144,36,64,40,192,36,80,41,32,27,112,41,218,123,32,41,234,123,0,52,80,57,
92732144,55,112,55,96,58,192,56,96,60,32,58,48,60,192,56,192,61,0,57,32,61,16,
9273357,128,61,80,58,96,61,96,58,0,61,112,60,240,63,0,57,160,63,16,58,16,63,32,
9273463,144,63,48,55,240,63,80,57,80,76,240,76,1,200,0,65,33,200,16,65,65,200,
9273532,65,225,200,80,66,33,200,96,66,161,200,112,70,33,200,138,100,161,215,154,
92736119,209,215,210,198,49,216,234,124,97,233,177,230,1,251,224,57,145,254,81,
92737254,194,20,226,19,34,24,66,24,50,198,18,198,2,198,80,35,162,198,96,35,226,
92738207,50,207,42,120,202,120,186,121,74,124,74,124,58,124,42,181,58,123,60,
92739192,27,240,2,152,2,152,10,76,5,120,0,156,3,225,0,37,1,134,1,200,96,115,32,
9274097,0,96,32,118,24,29,40,24,64,24,8,44,60,10,106,10,164,61,45,0,36,1,152,
92741143,75,192,10,128,97,3,211,16,2,184,24,80,244,204,0,178,6,20,61,53,0,32,
92742129,95,15,168,64,116,160,98,99,234,88,29,40,24,152,24,0,250,166,7,74,6,38,
927436,2,62,173,129,210,129,137,129,161,15,192,67,225,0,115,35,240,48,248,72,28,
92744200,252,20,62,20,7,50,63,7,15,133,129,204,143,194,67,225,128,115,35,240,
92745176,248,104,28,200,252,52,62,28,7,50,63,15,15,135,129,204,143,196,67,225,0,
92746115,35,241,48,248,72,28,200,252,84,62,20,7,50,63,23,15,133,129,204,143,198,
9274767,225,128,115,35,241,176,248,104,28,200,252,116,62,28,7,50,63,31,15,135,
92748129,204,143,200,67,229,0,115,35,242,48,249,72,28,200,252,148,62,84,7,50,63,
9274939,15,149,129,204,143,202,67,229,128,115,35,242,176,249,104,28,200,252,180,
9275062,92,7,50,63,47,15,151,129,204,143,204,67,229,0,115,35,243,48,249,72,28,
92751200,252,212,62,84,7,50,63,55,15,149,129,204,143,206,67,229,128,115,35,243,
92752176,249,104,28,200,252,244,62,92,7,50,63,63,15,151,129,204,143,208,67,237,
927530,115,35,244,48,251,72,28,200,253,20,62,212,7,50,63,71,15,181,129,204,143,
92754210,67,237,128,115,35,244,176,251,104,28,200,253,52,62,220,7,50,63,79,15,
92755183,129,204,143,212,67,237,0,115,35,245,48,251,72,28,200,253,84,62,212,7,
9275650,63,87,15,181,129,204,143,214,67,237,128,115,35,245,176,251,104,28,200,
92757253,116,62,220,7,50,63,95,15,183,129,204,143,217,67,247,64,115,35,246,112,
9275828,136,28,200,253,164,7,12,7,50,63,109,1,200,129,161,15,219,224,114,32,104,
9275964,115,35,247,144,28,136,28,200,254,20,63,148,7,50,63,135,1,203,129,204,
92760143,226,64,113,32,115,35,248,208,28,184,26,16,254,62,7,46,6,132,7,50,63,
92761153,1,203,129,204,143,233,96,115,32,97,0,96,3,250,120,28,200,24,64,24,8,
92762254,180,7,50,6,132,63,175,129,204,129,132,1,161,15,241,96,116,160,97,0,96,
927633,252,120,29,40,24,64,24,8,255,36,7,66,6,38,63,205,1,210,129,161,15,243,
92764224,116,160,97,0,104,67,254,80,255,208,28,200,255,156,7,82,7,50,63,233,1,
92765199,129,204,143,251,64,117,32,104,67,254,248,29,72,26,16,28,200,255,228,7,
9276682,7,51,246,1,0,35,0,35,125,128,192,8,192,9,63,96,80,2,48,2,103,216,30,0,
92767140,0,140,0,147,246,9,128,35,0,35,0,38,125,130,192,10,96,10,159,96,208,2,
92768152,2,167,216,156,10,136,10,141,246,41,2,162,2,154,253,138,192,168,128,167,
92769127,98,208,42,112,42,55,216,188,10,136,10,122,
92770};
92771const duk_uint8_t duk_unicode_caseconv_lc[706] = {
92772160,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
92773235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
927740,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19,
92775240,19,248,12,57,32,33,160,172,114,244,67,244,24,248,64,248,0,129,241,129,
92776241,0,195,229,3,228,2,7,206,7,204,4,15,164,15,160,6,31,104,31,96,16,63,16,
9277763,0,32,126,96,126,64,64,253,64,253,0,129,251,129,251,0,67,247,67,238,0,
92778135,242,7,220,130,15,236,15,232,2,31,218,31,118,4,63,208,63,192,8,127,168,
92779125,232,16,255,192,251,192,33,255,161,247,192,68,44,4,46,4,9,45,137,52,13,
9278022,0,22,24,47,44,126,2,63,5,254,67,254,130,106,48,16,0,16,19,0,38,64,38,96,
92781192,78,64,78,132,0,165,0,165,151,1,121,1,122,6,3,4,3,6,8,6,128,6,132,24,13,
92782152,13,160,32,28,176,28,193,32,59,192,59,226,64,124,128,124,193,0,252,0,
92783252,148,2,34,2,35,18,4,140,4,142,20,13,192,13,196,16,30,192,30,200,192,70,
927840,70,18,32,145,64,145,102,193,48,65,48,131,130,104,2,104,176,30,0,30,1,150,
9278561,64,61,66,192,125,100,125,68,33,99,57,99,64,50,200,2,200,22,69,157,101,
92786157,128,169,144,41,144,75,211,64,83,64,142,167,34,167,35,15,78,101,78,102,
92787126,157,230,157,232,21,59,245,59,248,90,121,10,121,16,84,242,212,242,226,
92788169,237,41,237,67,12,3,76,5,0,8,6,176,6,180,16,14,32,14,48,48,28,80,28,96,
9278964,126,224,127,0,139,28,139,28,193,6,3,14,3,16,8,6,224,6,228,21,61,80,19,
9279048,32,3,1,150,2,105,4,4,118,4,120,8,67,28,180,156,23,240,192,94,0,63,192,
9279196,64,148,192,97,128,149,0,99,128,119,64,99,192,150,64,100,0,150,192,100,
9279264,100,128,100,192,152,0,101,0,152,192,101,192,154,0,102,0,102,64,103,64,
92793156,128,103,192,157,64,105,192,106,0,107,128,162,0,109,192,164,128,124,64,
92794124,192,125,128,101,64,125,192,111,192,136,0,103,128,142,139,25,64,143,64,
92795102,128,143,139,25,128,144,192,96,0,145,0,162,64,145,64,163,0,221,128,221,
92796192,223,192,252,192,225,128,235,0,227,0,243,0,243,192,245,192,253,0,238,0,
92797254,64,252,129,48,1,51,199,167,128,55,199,239,7,236,199,243,7,240,199,251,
927987,249,71,255,7,252,200,73,128,242,72,74,128,26,200,74,192,57,72,76,136,83,
92799136,96,200,97,11,24,11,24,75,24,128,154,203,24,199,95,75,25,0,159,75,27,64,
92800148,75,27,128,156,75,27,192,148,11,28,0,148,139,60,139,60,233,223,71,94,
92801105,226,233,227,41,227,64,153,105,234,192,151,41,235,0,152,105,235,64,155,
9280241,236,0,167,169,236,64,161,233,236,128,167,105,236,234,212,233,240,169,
92803240,233,241,41,229,41,241,64,160,169,241,135,99,128,128,152,64,13,32,96,
92804224,
92805};
92806
92807#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
92808/*
92809 * Automatically generated by extract_caseconv.py, do not edit!
92810 */
92811
92812const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
928130,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,
9281428,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
9281553,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
9281678,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
9281771,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
92818126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
92819144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
92820162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
92821180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
92822198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
92823216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
92824202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
92825220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
92826270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
92827288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
92828306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
92829323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
92830342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
92831360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
92832377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
92833395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
92834544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
92835431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
92836450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
92837467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
92838486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
92839504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
92840522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
92841540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
92842558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
9284311391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
9284411373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403,
9284542924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622,
92846412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639,
92847422,641,42949L,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656,
92848657,439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673,
92849674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,
92850692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,
92851710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,
92852728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,
92853746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,
92854764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,
92855782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,
92856800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,
92857818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,
92858836,921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,
92859854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,
92860872,873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889,
92861890,1021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907,
92862908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,
92863926,927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906,
92864944,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,
92865931,931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979,
92866980,934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996,
92867998,998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917,
928681014,1015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,
928691029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,
928701044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,
928711059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,
928721042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,
928731057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,
928741024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,
928751039,1120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,
928761134,1134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,
928771148,1150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,
928781164,1164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,
928791178,1180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,
928801194,1194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,
928811208,1210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,
928821223,1225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,
928831238,1240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,
928841254,1254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,
928851268,1270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,
928861284,1284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,
928871298,1300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,
928881314,1314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328,
928891329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,
928901344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,
928911359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,
928921374,1375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,
928931341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,
928941356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,
928951419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,
928961434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,
928971449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,
928981464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,
928991479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,
929001494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,
929011509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,
929021524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,
929031539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,
929041554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,
929051569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,
929061584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,
929071599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,
929081614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,
929091629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,
929101644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,
929111659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,
929121674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,
929131689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,
929141704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,
929151719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,
929161734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,
929171749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,
929181764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,
929191779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,
929201794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,
929211809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,
929221824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,
929231839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,
929241854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,
929251869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,
929261884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,
929271899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,
929281914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,
929291929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,
929301944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,
929311959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,
929321974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,
929331989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,
929342004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,
929352019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,
929362034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,
929372049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,
929382064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,
929392079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,
929402094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,
929412109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,
929422124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,
929432139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,
929442154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,
929452169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,
929462184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,
929472199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,
929482214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,
929492229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,
929502244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,
929512259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,
929522274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,
929532289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,
929542304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,
929552319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,
929562334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,
929572349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,
929582364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,
929592379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,
929602394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,
929612409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,
929622424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,
929632439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,
929642454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,
929652469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,
929662484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,
929672499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,
929682514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,
929692529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,
929702544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,
929712559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,
929722574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,
929732589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,
929742604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,
929752619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,
929762634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,
929772649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,
929782664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,
929792679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,
929802694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,
929812709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,
929822724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,
929832739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,
929842754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,
929852769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,
929862784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,
929872799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,
929882814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,
929892829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,
929902844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,
929912859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,
929922874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,
929932889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,
929942904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,
929952919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,
929962934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,
929972949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,
929982964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,
929992979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,
930002994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,
930013009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,
930023024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,
930033039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,
930043054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,
930053069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,
930063084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,
930073099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,
930083114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,
930093129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,
930103144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,
930113159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,
930123174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,
930133189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,
930143204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,
930153219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,
930163234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,
930173249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,
930183264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,
930193279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,
930203294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,
930213309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,
930223324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,
930233339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,
930243354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,
930253369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,
930263384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,
930273399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,
930283414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,
930293429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,
930303444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,
930313459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,
930323474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,
930333489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,
930343504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,
930353519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,
930363534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,
930373549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,
930383564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,
930393579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,
930403594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,
930413609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,
930423624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,
930433639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,
930443654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,
930453669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,
930463684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,
930473699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,
930483714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,
930493729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,
930503744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,
930513759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,
930523774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,
930533789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,
930543804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,
930553819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,
930563834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,
930573849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,
930583864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,
930593879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,
930603894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,
930613909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,
930623924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,
930633939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,
930643954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,
930653969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,
930663984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,
930673999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,
930684014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,
930694029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,
930704044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,
930714059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,
930724074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,
930734089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,
930744104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,
930754119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,
930764134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,
930774149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,
930784164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,
930794179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,
930804194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,
930814209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,
930824224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,
930834239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,
930844254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,
930854269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,
930864284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,
930874299,4300,4301,4302,4303,7312,7313,7314,7315,7316,7317,7318,7319,7320,7321,
930887322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336,
930897337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,
930907352,7353,7354,4347,4348,7357,7358,7359,4352,4353,4354,4355,4356,4357,4358,
930914359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,
930924374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,
930934389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,
930944404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,
930954419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,
930964434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,
930974449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,
930984464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,
930994479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,
931004494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,
931014509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,
931024524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,
931034539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,
931044554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,
931054569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,
931064584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,
931074599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,
931084614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,
931094629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,
931104644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,
931114659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,
931124674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,
931134689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,
931144704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,
931154719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,
931164734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,
931174749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,
931184764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,
931194779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,
931204794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,
931214809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,
931224824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,
931234839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,
931244854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,
931254869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,
931264884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,
931274899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,
931284914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,
931294929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,
931304944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,
931314959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,
931324974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,
931334989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,
931345004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,
931355019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,
931365034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,
931375049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,
931385064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,
931395079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,
931405094,5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,
931415109,5110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123,
931425124,5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,
931435139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,
931445154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,
931455169,5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,
931465184,5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,
931475199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,
931485214,5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,
931495229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,
931505244,5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,
931515259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,
931525274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,
931535289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,
931545304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,
931555319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,
931565334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,
931575349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,
931585364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,
931595379,5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,
931605394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,
931615409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,
931625424,5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,
931635439,5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,
931645454,5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,
931655469,5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,
931665484,5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,
931675499,5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,
931685514,5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,
931695529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,
931705544,5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,
931715559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,
931725574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,
931735589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,
931745604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,
931755619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,
931765634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,
931775649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,
931785664,5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,
931795679,5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,
931805694,5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,
931815709,5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,
931825724,5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,
931835739,5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,
931845754,5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,
931855769,5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,
931865784,5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,
931875799,5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,
931885814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,
931895829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,
931905844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,
931915859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,
931925874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,
931935889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,
931945904,5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,
931955919,5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,
931965934,5935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,
931975949,5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,
931985964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,
931995979,5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,
932005994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,
932016009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,
932026024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,
932036039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,
932046054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,
932056069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,
932066084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,
932076099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,
932086114,6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,
932096129,6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,
932106144,6145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,
932116159,6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,
932126174,6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,
932136189,6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,
932146204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,
932156219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,
932166234,6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,
932176249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,
932186264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,
932196279,6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,
932206294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,
932216309,6310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,
932226324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,
932236339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,
932246354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,
932256369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,
932266384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,
932276399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,
932286414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,
932296429,6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,
932306444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,
932316459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,
932326474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,
932336489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,
932346504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,
932356519,6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,
932366534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,
932376549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,
932386564,6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,
932396579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,
932406594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,
932416609,6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,
932426624,6625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,
932436639,6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,
932446654,6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,
932456669,6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,
932466684,6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,
932476699,6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,
932486714,6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,
932496729,6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,
932506744,6745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,
932516759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,
932526774,6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,
932536789,6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,
932546804,6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,
932556819,6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,
932566834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,
932576849,6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,
932586864,6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,
932596879,6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,
932606894,6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,
932616909,6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,
932626924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,
932636939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,
932646954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,
932656969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,
932666984,6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,
932676999,7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,
932687014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,
932697029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,
932707044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,
932717059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,
932727074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,
932737089,7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,
932747104,7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,
932757119,7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,
932767134,7135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,
932777149,7150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,
932787164,7165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,
932797179,7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,
932807194,7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,
932817209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,
932827224,7225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,
932837239,7240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,
932847254,7255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,
932857269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,
932867284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054,
932871057,1058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312,
932887313,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,
932897328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,
932907343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,
932917358,7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,
932927373,7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,
932937388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,
932947403,7404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,
932957418,7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432,
932967433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,
932977448,7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,
932987463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,
932997478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,
933007493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,
933017508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,
933027523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,
933037538,7539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551,
933047552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,
9330542950L,7567,7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,
933067580,7581,7582,7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,
933077595,7596,7597,7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,
933087610,7611,7612,7613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624,
933097625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,
933107640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,
933117655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,
933127670,7671,7672,7673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684,
933137684,7686,7686,7688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698,
933147700,7700,7702,7702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714,
933157714,7716,7716,7718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728,
933167730,7730,7732,7732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744,
933177744,7746,7746,7748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758,
933187760,7760,7762,7762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774,
933197774,7776,7776,7778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788,
933207790,7790,7792,7792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804,
933217804,7806,7806,7808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818,
933227820,7820,7822,7822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834,
933237776,7836,7837,7838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848,
933247850,7850,7852,7852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864,
933257864,7866,7866,7868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878,
933267880,7880,7882,7882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894,
933277894,7896,7896,7898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908,
933287910,7910,7912,7912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924,
933297924,7926,7926,7928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947,
933307948,7949,7950,7951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962,
933317963,7964,7965,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977,
933327978,7979,7980,7981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992,
933337993,7994,7995,7996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999,
933348008,8009,8010,8011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014,
933358015,8016,8025,8018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029,
933368030,8031,8040,8041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044,
933378045,8046,8047,8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,
933388186,8187,8062,8063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,
933398075,8076,8077,8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,
933408090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,
933418105,8106,8107,8108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119,
933428120,8121,8122,8123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134,
933438135,8136,8137,8138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149,
933448150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164,
933458172,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,
933468180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,
933478195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,
933488210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,
933498225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,
933508240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,
933518255,8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,
933528270,8271,8272,8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,
933538285,8286,8287,8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,
933548300,8301,8302,8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,
933558315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,
933568330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,
933578345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,
933588360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,
933598375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,
933608390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,
933618405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,
933628420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,
933638435,8436,8437,8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,
933648450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,
933658465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,
933668480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,
933678495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,
933688510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,
933698525,8498,8527,8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,
933708540,8541,8542,8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,
933718555,8556,8557,8558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,
933728554,8555,8556,8557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584,
933738585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,
933748600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,
933758615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629,
933768630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,
933778645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,
933788660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,
933798675,8676,8677,8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,
933808690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,
933818705,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,
933828720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,
933838735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749,
933848750,8751,8752,8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764,
933858765,8766,8767,8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,
933868780,8781,8782,8783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794,
933878795,8796,8797,8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809,
933888810,8811,8812,8813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824,
933898825,8826,8827,8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839,
933908840,8841,8842,8843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854,
933918855,8856,8857,8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,
933928870,8871,8872,8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,
933938885,8886,8887,8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,
933948900,8901,8902,8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,
933958915,8916,8917,8918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,
933968930,8931,8932,8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944,
933978945,8946,8947,8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,
933988960,8961,8962,8963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974,
933998975,8976,8977,8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,
934008990,8991,8992,8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,
934019005,9006,9007,9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,
934029020,9021,9022,9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,
934039035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,
934049050,9051,9052,9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,
934059065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,
934069080,9081,9082,9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,
934079095,9096,9097,9098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109,
934089110,9111,9112,9113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124,
934099125,9126,9127,9128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139,
934109140,9141,9142,9143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154,
934119155,9156,9157,9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,
934129170,9171,9172,9173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184,
934139185,9186,9187,9188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199,
934149200,9201,9202,9203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214,
934159215,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,
934169230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,
934179245,9246,9247,9248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259,
934189260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274,
934199275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,
934209290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304,
934219305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,
934229320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334,
934239335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,
934249350,9351,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,
934259365,9366,9367,9368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379,
934269380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,
934279395,9396,9397,9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,
934289410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398,
934299399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,
934309414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454,
934319455,9456,9457,9458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469,
934329470,9471,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,
934339485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,
934349500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,
934359515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,
934369530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,
934379545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,
934389560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,
934399575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589,
934409590,9591,9592,9593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604,
934419605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,
934429620,9621,9622,9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634,
934439635,9636,9637,9638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649,
934449650,9651,9652,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,
934459665,9666,9667,9668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679,
934469680,9681,9682,9683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694,
934479695,9696,9697,9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,
934489710,9711,9712,9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,
934499725,9726,9727,9728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739,
934509740,9741,9742,9743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754,
934519755,9756,9757,9758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769,
934529770,9771,9772,9773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784,
934539785,9786,9787,9788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799,
934549800,9801,9802,9803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814,
934559815,9816,9817,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,
934569830,9831,9832,9833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844,
934579845,9846,9847,9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,
934589860,9861,9862,9863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874,
934599875,9876,9877,9878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889,
934609890,9891,9892,9893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904,
934619905,9906,9907,9908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919,
934629920,9921,9922,9923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934,
934639935,9936,9937,9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,
934649950,9951,9952,9953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964,
934659965,9966,9967,9968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979,
934669980,9981,9982,9983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994,
934679995,9996,9997,9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,
9346810008,10009,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,
9346910020,10021,10022,10023,10024,10025,10026,10027,10028,10029,10030,10031,
9347010032,10033,10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,
9347110044,10045,10046,10047,10048,10049,10050,10051,10052,10053,10054,10055,
9347210056,10057,10058,10059,10060,10061,10062,10063,10064,10065,10066,10067,
9347310068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,
9347410080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,
9347510092,10093,10094,10095,10096,10097,10098,10099,10100,10101,10102,10103,
9347610104,10105,10106,10107,10108,10109,10110,10111,10112,10113,10114,10115,
9347710116,10117,10118,10119,10120,10121,10122,10123,10124,10125,10126,10127,
9347810128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,
9347910140,10141,10142,10143,10144,10145,10146,10147,10148,10149,10150,10151,
9348010152,10153,10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,
9348110164,10165,10166,10167,10168,10169,10170,10171,10172,10173,10174,10175,
9348210176,10177,10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,
9348310188,10189,10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,
9348410200,10201,10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,
9348510212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,
9348610224,10225,10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,
9348710236,10237,10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,
9348810248,10249,10250,10251,10252,10253,10254,10255,10256,10257,10258,10259,
9348910260,10261,10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,
9349010272,10273,10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,
9349110284,10285,10286,10287,10288,10289,10290,10291,10292,10293,10294,10295,
9349210296,10297,10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,
9349310308,10309,10310,10311,10312,10313,10314,10315,10316,10317,10318,10319,
9349410320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,
9349510332,10333,10334,10335,10336,10337,10338,10339,10340,10341,10342,10343,
9349610344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354,10355,
9349710356,10357,10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,
9349810368,10369,10370,10371,10372,10373,10374,10375,10376,10377,10378,10379,
9349910380,10381,10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,
9350010392,10393,10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,
9350110404,10405,10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,
9350210416,10417,10418,10419,10420,10421,10422,10423,10424,10425,10426,10427,
9350310428,10429,10430,10431,10432,10433,10434,10435,10436,10437,10438,10439,
9350410440,10441,10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,
9350510452,10453,10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,
9350610464,10465,10466,10467,10468,10469,10470,10471,10472,10473,10474,10475,
9350710476,10477,10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,
9350810488,10489,10490,10491,10492,10493,10494,10495,10496,10497,10498,10499,
9350910500,10501,10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,
9351010512,10513,10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,
9351110524,10525,10526,10527,10528,10529,10530,10531,10532,10533,10534,10535,
9351210536,10537,10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,
9351310548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,
9351410560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,
9351510572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,
9351610584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,
9351710596,10597,10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,
9351810608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618,10619,
9351910620,10621,10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,
9352010632,10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,
9352110644,10645,10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,
9352210656,10657,10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,
9352310668,10669,10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,
9352410680,10681,10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,
9352510692,10693,10694,10695,10696,10697,10698,10699,10700,10701,10702,10703,
9352610704,10705,10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,
9352710716,10717,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,
9352810728,10729,10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,
9352910740,10741,10742,10743,10744,10745,10746,10747,10748,10749,10750,10751,
9353010752,10753,10754,10755,10756,10757,10758,10759,10760,10761,10762,10763,
9353110764,10765,10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,
9353210776,10777,10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,
9353310788,10789,10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,
9353410800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,
9353510812,10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,
9353610824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,
9353710836,10837,10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,
9353810848,10849,10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,
9353910860,10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,
9354010872,10873,10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,
9354110884,10885,10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,
9354210896,10897,10898,10899,10900,10901,10902,10903,10904,10905,10906,10907,
9354310908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,
9354410920,10921,10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,
9354510932,10933,10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,
9354610944,10945,10946,10947,10948,10949,10950,10951,10952,10953,10954,10955,
9354710956,10957,10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,
9354810968,10969,10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,
9354910980,10981,10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,
9355010992,10993,10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,
9355111004,11005,11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,
9355211016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,
9355311028,11029,11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,
9355411040,11041,11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,
9355511052,11053,11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,
9355611064,11065,11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,
9355711076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,
9355811088,11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,
9355911100,11101,11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,
9356011112,11113,11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,
9356111124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,
9356211136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,
9356311148,11149,11150,11151,11152,11153,11154,11155,11156,11157,11158,11159,
9356411160,11161,11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,
9356511172,11173,11174,11175,11176,11177,11178,11179,11180,11181,11182,11183,
9356611184,11185,11186,11187,11188,11189,11190,11191,11192,11193,11194,11195,
9356711196,11197,11198,11199,11200,11201,11202,11203,11204,11205,11206,11207,
9356811208,11209,11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,
9356911220,11221,11222,11223,11224,11225,11226,11227,11228,11229,11230,11231,
9357011232,11233,11234,11235,11236,11237,11238,11239,11240,11241,11242,11243,
9357111244,11245,11246,11247,11248,11249,11250,11251,11252,11253,11254,11255,
9357211256,11257,11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,
9357311268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,
9357411280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,
9357511292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,
9357611304,11305,11306,11307,11308,11309,11310,11311,11264,11265,11266,11267,
9357711268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,
9357811280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,
9357911292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,
9358011304,11305,11306,11307,11308,11309,11310,11359,11360,11360,11362,11363,
9358111364,570,574,11367,11367,11369,11369,11371,11371,11373,11374,11375,11376,
9358211377,11378,11378,11380,11381,11381,11383,11384,11385,11386,11387,11388,
9358311389,11390,11391,11392,11392,11394,11394,11396,11396,11398,11398,11400,
9358411400,11402,11402,11404,11404,11406,11406,11408,11408,11410,11410,11412,
9358511412,11414,11414,11416,11416,11418,11418,11420,11420,11422,11422,11424,
9358611424,11426,11426,11428,11428,11430,11430,11432,11432,11434,11434,11436,
9358711436,11438,11438,11440,11440,11442,11442,11444,11444,11446,11446,11448,
9358811448,11450,11450,11452,11452,11454,11454,11456,11456,11458,11458,11460,
9358911460,11462,11462,11464,11464,11466,11466,11468,11468,11470,11470,11472,
9359011472,11474,11474,11476,11476,11478,11478,11480,11480,11482,11482,11484,
9359111484,11486,11486,11488,11488,11490,11490,11492,11493,11494,11495,11496,
9359211497,11498,11499,11499,11501,11501,11503,11504,11505,11506,11506,11508,
9359311509,11510,11511,11512,11513,11514,11515,11516,11517,11518,11519,4256,
935944257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,
935954272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,
935964287,4288,4289,4290,4291,4292,4293,11558,4295,11560,11561,11562,11563,
9359711564,4301,11566,11567,11568,11569,11570,11571,11572,11573,11574,11575,
9359811576,11577,11578,11579,11580,11581,11582,11583,11584,11585,11586,11587,
9359911588,11589,11590,11591,11592,11593,11594,11595,11596,11597,11598,11599,
9360011600,11601,11602,11603,11604,11605,11606,11607,11608,11609,11610,11611,
9360111612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622,11623,
9360211624,11625,11626,11627,11628,11629,11630,11631,11632,11633,11634,11635,
9360311636,11637,11638,11639,11640,11641,11642,11643,11644,11645,11646,11647,
9360411648,11649,11650,11651,11652,11653,11654,11655,11656,11657,11658,11659,
9360511660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670,11671,
9360611672,11673,11674,11675,11676,11677,11678,11679,11680,11681,11682,11683,
9360711684,11685,11686,11687,11688,11689,11690,11691,11692,11693,11694,11695,
9360811696,11697,11698,11699,11700,11701,11702,11703,11704,11705,11706,11707,
9360911708,11709,11710,11711,11712,11713,11714,11715,11716,11717,11718,11719,
9361011720,11721,11722,11723,11724,11725,11726,11727,11728,11729,11730,11731,
9361111732,11733,11734,11735,11736,11737,11738,11739,11740,11741,11742,11743,
9361211744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755,
9361311756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,
9361411768,11769,11770,11771,11772,11773,11774,11775,11776,11777,11778,11779,
9361511780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,11791,
9361611792,11793,11794,11795,11796,11797,11798,11799,11800,11801,11802,11803,
9361711804,11805,11806,11807,11808,11809,11810,11811,11812,11813,11814,11815,
9361811816,11817,11818,11819,11820,11821,11822,11823,11824,11825,11826,11827,
9361911828,11829,11830,11831,11832,11833,11834,11835,11836,11837,11838,11839,
9362011840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850,11851,
9362111852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,
9362211864,11865,11866,11867,11868,11869,11870,11871,11872,11873,11874,11875,
9362311876,11877,11878,11879,11880,11881,11882,11883,11884,11885,11886,11887,
9362411888,11889,11890,11891,11892,11893,11894,11895,11896,11897,11898,11899,
9362511900,11901,11902,11903,11904,11905,11906,11907,11908,11909,11910,11911,
9362611912,11913,11914,11915,11916,11917,11918,11919,11920,11921,11922,11923,
9362711924,11925,11926,11927,11928,11929,11930,11931,11932,11933,11934,11935,
9362811936,11937,11938,11939,11940,11941,11942,11943,11944,11945,11946,11947,
9362911948,11949,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959,
9363011960,11961,11962,11963,11964,11965,11966,11967,11968,11969,11970,11971,
9363111972,11973,11974,11975,11976,11977,11978,11979,11980,11981,11982,11983,
9363211984,11985,11986,11987,11988,11989,11990,11991,11992,11993,11994,11995,
9363311996,11997,11998,11999,12000,12001,12002,12003,12004,12005,12006,12007,
9363412008,12009,12010,12011,12012,12013,12014,12015,12016,12017,12018,12019,
9363512020,12021,12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,
9363612032,12033,12034,12035,12036,12037,12038,12039,12040,12041,12042,12043,
9363712044,12045,12046,12047,12048,12049,12050,12051,12052,12053,12054,12055,
9363812056,12057,12058,12059,12060,12061,12062,12063,12064,12065,12066,12067,
9363912068,12069,12070,12071,12072,12073,12074,12075,12076,12077,12078,12079,
9364012080,12081,12082,12083,12084,12085,12086,12087,12088,12089,12090,12091,
9364112092,12093,12094,12095,12096,12097,12098,12099,12100,12101,12102,12103,
9364212104,12105,12106,12107,12108,12109,12110,12111,12112,12113,12114,12115,
9364312116,12117,12118,12119,12120,12121,12122,12123,12124,12125,12126,12127,
9364412128,12129,12130,12131,12132,12133,12134,12135,12136,12137,12138,12139,
9364512140,12141,12142,12143,12144,12145,12146,12147,12148,12149,12150,12151,
9364612152,12153,12154,12155,12156,12157,12158,12159,12160,12161,12162,12163,
9364712164,12165,12166,12167,12168,12169,12170,12171,12172,12173,12174,12175,
9364812176,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187,
9364912188,12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,
9365012200,12201,12202,12203,12204,12205,12206,12207,12208,12209,12210,12211,
9365112212,12213,12214,12215,12216,12217,12218,12219,12220,12221,12222,12223,
9365212224,12225,12226,12227,12228,12229,12230,12231,12232,12233,12234,12235,
9365312236,12237,12238,12239,12240,12241,12242,12243,12244,12245,12246,12247,
9365412248,12249,12250,12251,12252,12253,12254,12255,12256,12257,12258,12259,
9365512260,12261,12262,12263,12264,12265,12266,12267,12268,12269,12270,12271,
9365612272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283,
9365712284,12285,12286,12287,12288,12289,12290,12291,12292,12293,12294,12295,
9365812296,12297,12298,12299,12300,12301,12302,12303,12304,12305,12306,12307,
9365912308,12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,
9366012320,12321,12322,12323,12324,12325,12326,12327,12328,12329,12330,12331,
9366112332,12333,12334,12335,12336,12337,12338,12339,12340,12341,12342,12343,
9366212344,12345,12346,12347,12348,12349,12350,12351,12352,12353,12354,12355,
9366312356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,
9366412368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,
9366512380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,
9366612392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,
9366712404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,
9366812416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,
9366912428,12429,12430,12431,12432,12433,12434,12435,12436,12437,12438,12439,
9367012440,12441,12442,12443,12444,12445,12446,12447,12448,12449,12450,12451,
9367112452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,
9367212464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,
9367312476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,
9367412488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,
9367512500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,
9367612512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,
9367712524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535,
9367812536,12537,12538,12539,12540,12541,12542,12543,12544,12545,12546,12547,
9367912548,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,
9368012560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,
9368112572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,
9368212584,12585,12586,12587,12588,12589,12590,12591,12592,12593,12594,12595,
9368312596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,
9368412608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,
9368512620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,
9368612632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,
9368712644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,
9368812656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,
9368912668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,
9369012680,12681,12682,12683,12684,12685,12686,12687,12688,12689,12690,12691,
9369112692,12693,12694,12695,12696,12697,12698,12699,12700,12701,12702,12703,
9369212704,12705,12706,12707,12708,12709,12710,12711,12712,12713,12714,12715,
9369312716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726,12727,
9369412728,12729,12730,12731,12732,12733,12734,12735,12736,12737,12738,12739,
9369512740,12741,12742,12743,12744,12745,12746,12747,12748,12749,12750,12751,
9369612752,12753,12754,12755,12756,12757,12758,12759,12760,12761,12762,12763,
9369712764,12765,12766,12767,12768,12769,12770,12771,12772,12773,12774,12775,
9369812776,12777,12778,12779,12780,12781,12782,12783,12784,12785,12786,12787,
9369912788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799,
9370012800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811,
9370112812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823,
9370212824,12825,12826,12827,12828,12829,12830,12831,12832,12833,12834,12835,
9370312836,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,12847,
9370412848,12849,12850,12851,12852,12853,12854,12855,12856,12857,12858,12859,
9370512860,12861,12862,12863,12864,12865,12866,12867,12868,12869,12870,12871,
9370612872,12873,12874,12875,12876,12877,12878,12879,12880,12881,12882,12883,
9370712884,12885,12886,12887,12888,12889,12890,12891,12892,12893,12894,12895,
9370812896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,
9370912908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919,
9371012920,12921,12922,12923,12924,12925,12926,12927,12928,12929,12930,12931,
9371112932,12933,12934,12935,12936,12937,12938,12939,12940,12941,12942,12943,
9371212944,12945,12946,12947,12948,12949,12950,12951,12952,12953,12954,12955,
9371312956,12957,12958,12959,12960,12961,12962,12963,12964,12965,12966,12967,
9371412968,12969,12970,12971,12972,12973,12974,12975,12976,12977,12978,12979,
9371512980,12981,12982,12983,12984,12985,12986,12987,12988,12989,12990,12991,
9371612992,12993,12994,12995,12996,12997,12998,12999,13000,13001,13002,13003,
9371713004,13005,13006,13007,13008,13009,13010,13011,13012,13013,13014,13015,
9371813016,13017,13018,13019,13020,13021,13022,13023,13024,13025,13026,13027,
9371913028,13029,13030,13031,13032,13033,13034,13035,13036,13037,13038,13039,
9372013040,13041,13042,13043,13044,13045,13046,13047,13048,13049,13050,13051,
9372113052,13053,13054,13055,13056,13057,13058,13059,13060,13061,13062,13063,
9372213064,13065,13066,13067,13068,13069,13070,13071,13072,13073,13074,13075,
9372313076,13077,13078,13079,13080,13081,13082,13083,13084,13085,13086,13087,
9372413088,13089,13090,13091,13092,13093,13094,13095,13096,13097,13098,13099,
9372513100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111,
9372613112,13113,13114,13115,13116,13117,13118,13119,13120,13121,13122,13123,
9372713124,13125,13126,13127,13128,13129,13130,13131,13132,13133,13134,13135,
9372813136,13137,13138,13139,13140,13141,13142,13143,13144,13145,13146,13147,
9372913148,13149,13150,13151,13152,13153,13154,13155,13156,13157,13158,13159,
9373013160,13161,13162,13163,13164,13165,13166,13167,13168,13169,13170,13171,
9373113172,13173,13174,13175,13176,13177,13178,13179,13180,13181,13182,13183,
9373213184,13185,13186,13187,13188,13189,13190,13191,13192,13193,13194,13195,
9373313196,13197,13198,13199,13200,13201,13202,13203,13204,13205,13206,13207,
9373413208,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13219,
9373513220,13221,13222,13223,13224,13225,13226,13227,13228,13229,13230,13231,
9373613232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13242,13243,
9373713244,13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,
9373813256,13257,13258,13259,13260,13261,13262,13263,13264,13265,13266,13267,
9373913268,13269,13270,13271,13272,13273,13274,13275,13276,13277,13278,13279,
9374013280,13281,13282,13283,13284,13285,13286,13287,13288,13289,13290,13291,
9374113292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,13303,
9374213304,13305,13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,
9374313316,13317,13318,13319,13320,13321,13322,13323,13324,13325,13326,13327,
9374413328,13329,13330,13331,13332,13333,13334,13335,13336,13337,13338,13339,
9374513340,13341,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351,
9374613352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,
9374713364,13365,13366,13367,13368,13369,13370,13371,13372,13373,13374,13375,
9374813376,13377,13378,13379,13380,13381,13382,13383,13384,13385,13386,13387,
9374913388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398,13399,
9375013400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,
9375113412,13413,13414,13415,13416,13417,13418,13419,13420,13421,13422,13423,
9375213424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435,
9375313436,13437,13438,13439,13440,13441,13442,13443,13444,13445,13446,13447,
9375413448,13449,13450,13451,13452,13453,13454,13455,13456,13457,13458,13459,
9375513460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,13471,
9375613472,13473,13474,13475,13476,13477,13478,13479,13480,13481,13482,13483,
9375713484,13485,13486,13487,13488,13489,13490,13491,13492,13493,13494,13495,
9375813496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506,13507,
9375913508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519,
9376013520,13521,13522,13523,13524,13525,13526,13527,13528,13529,13530,13531,
9376113532,13533,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543,
9376213544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555,
9376313556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,
9376413568,13569,13570,13571,13572,13573,13574,13575,13576,13577,13578,13579,
9376513580,13581,13582,13583,13584,13585,13586,13587,13588,13589,13590,13591,
9376613592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602,13603,
9376713604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,
9376813616,13617,13618,13619,13620,13621,13622,13623,13624,13625,13626,13627,
9376913628,13629,13630,13631,13632,13633,13634,13635,13636,13637,13638,13639,
9377013640,13641,13642,13643,13644,13645,13646,13647,13648,13649,13650,13651,
9377113652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,
9377213664,13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,
9377313676,13677,13678,13679,13680,13681,13682,13683,13684,13685,13686,13687,
9377413688,13689,13690,13691,13692,13693,13694,13695,13696,13697,13698,13699,
9377513700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,
9377613712,13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,
9377713724,13725,13726,13727,13728,13729,13730,13731,13732,13733,13734,13735,
9377813736,13737,13738,13739,13740,13741,13742,13743,13744,13745,13746,13747,
9377913748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,
9378013760,13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771,
9378113772,13773,13774,13775,13776,13777,13778,13779,13780,13781,13782,13783,
9378213784,13785,13786,13787,13788,13789,13790,13791,13792,13793,13794,13795,
9378313796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807,
9378413808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819,
9378513820,13821,13822,13823,13824,13825,13826,13827,13828,13829,13830,13831,
9378613832,13833,13834,13835,13836,13837,13838,13839,13840,13841,13842,13843,
9378713844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855,
9378813856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867,
9378913868,13869,13870,13871,13872,13873,13874,13875,13876,13877,13878,13879,
9379013880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13890,13891,
9379113892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903,
9379213904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915,
9379313916,13917,13918,13919,13920,13921,13922,13923,13924,13925,13926,13927,
9379413928,13929,13930,13931,13932,13933,13934,13935,13936,13937,13938,13939,
9379513940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951,
9379613952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,
9379713964,13965,13966,13967,13968,13969,13970,13971,13972,13973,13974,13975,
9379813976,13977,13978,13979,13980,13981,13982,13983,13984,13985,13986,13987,
9379913988,13989,13990,13991,13992,13993,13994,13995,13996,13997,13998,13999,
9380014000,14001,14002,14003,14004,14005,14006,14007,14008,14009,14010,14011,
9380114012,14013,14014,14015,14016,14017,14018,14019,14020,14021,14022,14023,
9380214024,14025,14026,14027,14028,14029,14030,14031,14032,14033,14034,14035,
9380314036,14037,14038,14039,14040,14041,14042,14043,14044,14045,14046,14047,
9380414048,14049,14050,14051,14052,14053,14054,14055,14056,14057,14058,14059,
9380514060,14061,14062,14063,14064,14065,14066,14067,14068,14069,14070,14071,
9380614072,14073,14074,14075,14076,14077,14078,14079,14080,14081,14082,14083,
9380714084,14085,14086,14087,14088,14089,14090,14091,14092,14093,14094,14095,
9380814096,14097,14098,14099,14100,14101,14102,14103,14104,14105,14106,14107,
9380914108,14109,14110,14111,14112,14113,14114,14115,14116,14117,14118,14119,
9381014120,14121,14122,14123,14124,14125,14126,14127,14128,14129,14130,14131,
9381114132,14133,14134,14135,14136,14137,14138,14139,14140,14141,14142,14143,
9381214144,14145,14146,14147,14148,14149,14150,14151,14152,14153,14154,14155,
9381314156,14157,14158,14159,14160,14161,14162,14163,14164,14165,14166,14167,
9381414168,14169,14170,14171,14172,14173,14174,14175,14176,14177,14178,14179,
9381514180,14181,14182,14183,14184,14185,14186,14187,14188,14189,14190,14191,
9381614192,14193,14194,14195,14196,14197,14198,14199,14200,14201,14202,14203,
9381714204,14205,14206,14207,14208,14209,14210,14211,14212,14213,14214,14215,
9381814216,14217,14218,14219,14220,14221,14222,14223,14224,14225,14226,14227,
9381914228,14229,14230,14231,14232,14233,14234,14235,14236,14237,14238,14239,
9382014240,14241,14242,14243,14244,14245,14246,14247,14248,14249,14250,14251,
9382114252,14253,14254,14255,14256,14257,14258,14259,14260,14261,14262,14263,
9382214264,14265,14266,14267,14268,14269,14270,14271,14272,14273,14274,14275,
9382314276,14277,14278,14279,14280,14281,14282,14283,14284,14285,14286,14287,
9382414288,14289,14290,14291,14292,14293,14294,14295,14296,14297,14298,14299,
9382514300,14301,14302,14303,14304,14305,14306,14307,14308,14309,14310,14311,
9382614312,14313,14314,14315,14316,14317,14318,14319,14320,14321,14322,14323,
9382714324,14325,14326,14327,14328,14329,14330,14331,14332,14333,14334,14335,
9382814336,14337,14338,14339,14340,14341,14342,14343,14344,14345,14346,14347,
9382914348,14349,14350,14351,14352,14353,14354,14355,14356,14357,14358,14359,
9383014360,14361,14362,14363,14364,14365,14366,14367,14368,14369,14370,14371,
9383114372,14373,14374,14375,14376,14377,14378,14379,14380,14381,14382,14383,
9383214384,14385,14386,14387,14388,14389,14390,14391,14392,14393,14394,14395,
9383314396,14397,14398,14399,14400,14401,14402,14403,14404,14405,14406,14407,
9383414408,14409,14410,14411,14412,14413,14414,14415,14416,14417,14418,14419,
9383514420,14421,14422,14423,14424,14425,14426,14427,14428,14429,14430,14431,
9383614432,14433,14434,14435,14436,14437,14438,14439,14440,14441,14442,14443,
9383714444,14445,14446,14447,14448,14449,14450,14451,14452,14453,14454,14455,
9383814456,14457,14458,14459,14460,14461,14462,14463,14464,14465,14466,14467,
9383914468,14469,14470,14471,14472,14473,14474,14475,14476,14477,14478,14479,
9384014480,14481,14482,14483,14484,14485,14486,14487,14488,14489,14490,14491,
9384114492,14493,14494,14495,14496,14497,14498,14499,14500,14501,14502,14503,
9384214504,14505,14506,14507,14508,14509,14510,14511,14512,14513,14514,14515,
9384314516,14517,14518,14519,14520,14521,14522,14523,14524,14525,14526,14527,
9384414528,14529,14530,14531,14532,14533,14534,14535,14536,14537,14538,14539,
9384514540,14541,14542,14543,14544,14545,14546,14547,14548,14549,14550,14551,
9384614552,14553,14554,14555,14556,14557,14558,14559,14560,14561,14562,14563,
9384714564,14565,14566,14567,14568,14569,14570,14571,14572,14573,14574,14575,
9384814576,14577,14578,14579,14580,14581,14582,14583,14584,14585,14586,14587,
9384914588,14589,14590,14591,14592,14593,14594,14595,14596,14597,14598,14599,
9385014600,14601,14602,14603,14604,14605,14606,14607,14608,14609,14610,14611,
9385114612,14613,14614,14615,14616,14617,14618,14619,14620,14621,14622,14623,
9385214624,14625,14626,14627,14628,14629,14630,14631,14632,14633,14634,14635,
9385314636,14637,14638,14639,14640,14641,14642,14643,14644,14645,14646,14647,
9385414648,14649,14650,14651,14652,14653,14654,14655,14656,14657,14658,14659,
9385514660,14661,14662,14663,14664,14665,14666,14667,14668,14669,14670,14671,
9385614672,14673,14674,14675,14676,14677,14678,14679,14680,14681,14682,14683,
9385714684,14685,14686,14687,14688,14689,14690,14691,14692,14693,14694,14695,
9385814696,14697,14698,14699,14700,14701,14702,14703,14704,14705,14706,14707,
9385914708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719,
9386014720,14721,14722,14723,14724,14725,14726,14727,14728,14729,14730,14731,
9386114732,14733,14734,14735,14736,14737,14738,14739,14740,14741,14742,14743,
9386214744,14745,14746,14747,14748,14749,14750,14751,14752,14753,14754,14755,
9386314756,14757,14758,14759,14760,14761,14762,14763,14764,14765,14766,14767,
9386414768,14769,14770,14771,14772,14773,14774,14775,14776,14777,14778,14779,
9386514780,14781,14782,14783,14784,14785,14786,14787,14788,14789,14790,14791,
9386614792,14793,14794,14795,14796,14797,14798,14799,14800,14801,14802,14803,
9386714804,14805,14806,14807,14808,14809,14810,14811,14812,14813,14814,14815,
9386814816,14817,14818,14819,14820,14821,14822,14823,14824,14825,14826,14827,
9386914828,14829,14830,14831,14832,14833,14834,14835,14836,14837,14838,14839,
9387014840,14841,14842,14843,14844,14845,14846,14847,14848,14849,14850,14851,
9387114852,14853,14854,14855,14856,14857,14858,14859,14860,14861,14862,14863,
9387214864,14865,14866,14867,14868,14869,14870,14871,14872,14873,14874,14875,
9387314876,14877,14878,14879,14880,14881,14882,14883,14884,14885,14886,14887,
9387414888,14889,14890,14891,14892,14893,14894,14895,14896,14897,14898,14899,
9387514900,14901,14902,14903,14904,14905,14906,14907,14908,14909,14910,14911,
9387614912,14913,14914,14915,14916,14917,14918,14919,14920,14921,14922,14923,
9387714924,14925,14926,14927,14928,14929,14930,14931,14932,14933,14934,14935,
9387814936,14937,14938,14939,14940,14941,14942,14943,14944,14945,14946,14947,
9387914948,14949,14950,14951,14952,14953,14954,14955,14956,14957,14958,14959,
9388014960,14961,14962,14963,14964,14965,14966,14967,14968,14969,14970,14971,
9388114972,14973,14974,14975,14976,14977,14978,14979,14980,14981,14982,14983,
9388214984,14985,14986,14987,14988,14989,14990,14991,14992,14993,14994,14995,
9388314996,14997,14998,14999,15000,15001,15002,15003,15004,15005,15006,15007,
9388415008,15009,15010,15011,15012,15013,15014,15015,15016,15017,15018,15019,
9388515020,15021,15022,15023,15024,15025,15026,15027,15028,15029,15030,15031,
9388615032,15033,15034,15035,15036,15037,15038,15039,15040,15041,15042,15043,
9388715044,15045,15046,15047,15048,15049,15050,15051,15052,15053,15054,15055,
9388815056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067,
9388915068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079,
9389015080,15081,15082,15083,15084,15085,15086,15087,15088,15089,15090,15091,
9389115092,15093,15094,15095,15096,15097,15098,15099,15100,15101,15102,15103,
9389215104,15105,15106,15107,15108,15109,15110,15111,15112,15113,15114,15115,
9389315116,15117,15118,15119,15120,15121,15122,15123,15124,15125,15126,15127,
9389415128,15129,15130,15131,15132,15133,15134,15135,15136,15137,15138,15139,
9389515140,15141,15142,15143,15144,15145,15146,15147,15148,15149,15150,15151,
9389615152,15153,15154,15155,15156,15157,15158,15159,15160,15161,15162,15163,
9389715164,15165,15166,15167,15168,15169,15170,15171,15172,15173,15174,15175,
9389815176,15177,15178,15179,15180,15181,15182,15183,15184,15185,15186,15187,
9389915188,15189,15190,15191,15192,15193,15194,15195,15196,15197,15198,15199,
9390015200,15201,15202,15203,15204,15205,15206,15207,15208,15209,15210,15211,
9390115212,15213,15214,15215,15216,15217,15218,15219,15220,15221,15222,15223,
9390215224,15225,15226,15227,15228,15229,15230,15231,15232,15233,15234,15235,
9390315236,15237,15238,15239,15240,15241,15242,15243,15244,15245,15246,15247,
9390415248,15249,15250,15251,15252,15253,15254,15255,15256,15257,15258,15259,
9390515260,15261,15262,15263,15264,15265,15266,15267,15268,15269,15270,15271,
9390615272,15273,15274,15275,15276,15277,15278,15279,15280,15281,15282,15283,
9390715284,15285,15286,15287,15288,15289,15290,15291,15292,15293,15294,15295,
9390815296,15297,15298,15299,15300,15301,15302,15303,15304,15305,15306,15307,
9390915308,15309,15310,15311,15312,15313,15314,15315,15316,15317,15318,15319,
9391015320,15321,15322,15323,15324,15325,15326,15327,15328,15329,15330,15331,
9391115332,15333,15334,15335,15336,15337,15338,15339,15340,15341,15342,15343,
9391215344,15345,15346,15347,15348,15349,15350,15351,15352,15353,15354,15355,
9391315356,15357,15358,15359,15360,15361,15362,15363,15364,15365,15366,15367,
9391415368,15369,15370,15371,15372,15373,15374,15375,15376,15377,15378,15379,
9391515380,15381,15382,15383,15384,15385,15386,15387,15388,15389,15390,15391,
9391615392,15393,15394,15395,15396,15397,15398,15399,15400,15401,15402,15403,
9391715404,15405,15406,15407,15408,15409,15410,15411,15412,15413,15414,15415,
9391815416,15417,15418,15419,15420,15421,15422,15423,15424,15425,15426,15427,
9391915428,15429,15430,15431,15432,15433,15434,15435,15436,15437,15438,15439,
9392015440,15441,15442,15443,15444,15445,15446,15447,15448,15449,15450,15451,
9392115452,15453,15454,15455,15456,15457,15458,15459,15460,15461,15462,15463,
9392215464,15465,15466,15467,15468,15469,15470,15471,15472,15473,15474,15475,
9392315476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487,
9392415488,15489,15490,15491,15492,15493,15494,15495,15496,15497,15498,15499,
9392515500,15501,15502,15503,15504,15505,15506,15507,15508,15509,15510,15511,
9392615512,15513,15514,15515,15516,15517,15518,15519,15520,15521,15522,15523,
9392715524,15525,15526,15527,15528,15529,15530,15531,15532,15533,15534,15535,
9392815536,15537,15538,15539,15540,15541,15542,15543,15544,15545,15546,15547,
9392915548,15549,15550,15551,15552,15553,15554,15555,15556,15557,15558,15559,
9393015560,15561,15562,15563,15564,15565,15566,15567,15568,15569,15570,15571,
9393115572,15573,15574,15575,15576,15577,15578,15579,15580,15581,15582,15583,
9393215584,15585,15586,15587,15588,15589,15590,15591,15592,15593,15594,15595,
9393315596,15597,15598,15599,15600,15601,15602,15603,15604,15605,15606,15607,
9393415608,15609,15610,15611,15612,15613,15614,15615,15616,15617,15618,15619,
9393515620,15621,15622,15623,15624,15625,15626,15627,15628,15629,15630,15631,
9393615632,15633,15634,15635,15636,15637,15638,15639,15640,15641,15642,15643,
9393715644,15645,15646,15647,15648,15649,15650,15651,15652,15653,15654,15655,
9393815656,15657,15658,15659,15660,15661,15662,15663,15664,15665,15666,15667,
9393915668,15669,15670,15671,15672,15673,15674,15675,15676,15677,15678,15679,
9394015680,15681,15682,15683,15684,15685,15686,15687,15688,15689,15690,15691,
9394115692,15693,15694,15695,15696,15697,15698,15699,15700,15701,15702,15703,
9394215704,15705,15706,15707,15708,15709,15710,15711,15712,15713,15714,15715,
9394315716,15717,15718,15719,15720,15721,15722,15723,15724,15725,15726,15727,
9394415728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739,
9394515740,15741,15742,15743,15744,15745,15746,15747,15748,15749,15750,15751,
9394615752,15753,15754,15755,15756,15757,15758,15759,15760,15761,15762,15763,
9394715764,15765,15766,15767,15768,15769,15770,15771,15772,15773,15774,15775,
9394815776,15777,15778,15779,15780,15781,15782,15783,15784,15785,15786,15787,
9394915788,15789,15790,15791,15792,15793,15794,15795,15796,15797,15798,15799,
9395015800,15801,15802,15803,15804,15805,15806,15807,15808,15809,15810,15811,
9395115812,15813,15814,15815,15816,15817,15818,15819,15820,15821,15822,15823,
9395215824,15825,15826,15827,15828,15829,15830,15831,15832,15833,15834,15835,
9395315836,15837,15838,15839,15840,15841,15842,15843,15844,15845,15846,15847,
9395415848,15849,15850,15851,15852,15853,15854,15855,15856,15857,15858,15859,
9395515860,15861,15862,15863,15864,15865,15866,15867,15868,15869,15870,15871,
9395615872,15873,15874,15875,15876,15877,15878,15879,15880,15881,15882,15883,
9395715884,15885,15886,15887,15888,15889,15890,15891,15892,15893,15894,15895,
9395815896,15897,15898,15899,15900,15901,15902,15903,15904,15905,15906,15907,
9395915908,15909,15910,15911,15912,15913,15914,15915,15916,15917,15918,15919,
9396015920,15921,15922,15923,15924,15925,15926,15927,15928,15929,15930,15931,
9396115932,15933,15934,15935,15936,15937,15938,15939,15940,15941,15942,15943,
9396215944,15945,15946,15947,15948,15949,15950,15951,15952,15953,15954,15955,
9396315956,15957,15958,15959,15960,15961,15962,15963,15964,15965,15966,15967,
9396415968,15969,15970,15971,15972,15973,15974,15975,15976,15977,15978,15979,
9396515980,15981,15982,15983,15984,15985,15986,15987,15988,15989,15990,15991,
9396615992,15993,15994,15995,15996,15997,15998,15999,16000,16001,16002,16003,
9396716004,16005,16006,16007,16008,16009,16010,16011,16012,16013,16014,16015,
9396816016,16017,16018,16019,16020,16021,16022,16023,16024,16025,16026,16027,
9396916028,16029,16030,16031,16032,16033,16034,16035,16036,16037,16038,16039,
9397016040,16041,16042,16043,16044,16045,16046,16047,16048,16049,16050,16051,
9397116052,16053,16054,16055,16056,16057,16058,16059,16060,16061,16062,16063,
9397216064,16065,16066,16067,16068,16069,16070,16071,16072,16073,16074,16075,
9397316076,16077,16078,16079,16080,16081,16082,16083,16084,16085,16086,16087,
9397416088,16089,16090,16091,16092,16093,16094,16095,16096,16097,16098,16099,
9397516100,16101,16102,16103,16104,16105,16106,16107,16108,16109,16110,16111,
9397616112,16113,16114,16115,16116,16117,16118,16119,16120,16121,16122,16123,
9397716124,16125,16126,16127,16128,16129,16130,16131,16132,16133,16134,16135,
9397816136,16137,16138,16139,16140,16141,16142,16143,16144,16145,16146,16147,
9397916148,16149,16150,16151,16152,16153,16154,16155,16156,16157,16158,16159,
9398016160,16161,16162,16163,16164,16165,16166,16167,16168,16169,16170,16171,
9398116172,16173,16174,16175,16176,16177,16178,16179,16180,16181,16182,16183,
9398216184,16185,16186,16187,16188,16189,16190,16191,16192,16193,16194,16195,
9398316196,16197,16198,16199,16200,16201,16202,16203,16204,16205,16206,16207,
9398416208,16209,16210,16211,16212,16213,16214,16215,16216,16217,16218,16219,
9398516220,16221,16222,16223,16224,16225,16226,16227,16228,16229,16230,16231,
9398616232,16233,16234,16235,16236,16237,16238,16239,16240,16241,16242,16243,
9398716244,16245,16246,16247,16248,16249,16250,16251,16252,16253,16254,16255,
9398816256,16257,16258,16259,16260,16261,16262,16263,16264,16265,16266,16267,
9398916268,16269,16270,16271,16272,16273,16274,16275,16276,16277,16278,16279,
9399016280,16281,16282,16283,16284,16285,16286,16287,16288,16289,16290,16291,
9399116292,16293,16294,16295,16296,16297,16298,16299,16300,16301,16302,16303,
9399216304,16305,16306,16307,16308,16309,16310,16311,16312,16313,16314,16315,
9399316316,16317,16318,16319,16320,16321,16322,16323,16324,16325,16326,16327,
9399416328,16329,16330,16331,16332,16333,16334,16335,16336,16337,16338,16339,
9399516340,16341,16342,16343,16344,16345,16346,16347,16348,16349,16350,16351,
9399616352,16353,16354,16355,16356,16357,16358,16359,16360,16361,16362,16363,
9399716364,16365,16366,16367,16368,16369,16370,16371,16372,16373,16374,16375,
9399816376,16377,16378,16379,16380,16381,16382,16383,16384,16385,16386,16387,
9399916388,16389,16390,16391,16392,16393,16394,16395,16396,16397,16398,16399,
9400016400,16401,16402,16403,16404,16405,16406,16407,16408,16409,16410,16411,
9400116412,16413,16414,16415,16416,16417,16418,16419,16420,16421,16422,16423,
9400216424,16425,16426,16427,16428,16429,16430,16431,16432,16433,16434,16435,
9400316436,16437,16438,16439,16440,16441,16442,16443,16444,16445,16446,16447,
9400416448,16449,16450,16451,16452,16453,16454,16455,16456,16457,16458,16459,
9400516460,16461,16462,16463,16464,16465,16466,16467,16468,16469,16470,16471,
9400616472,16473,16474,16475,16476,16477,16478,16479,16480,16481,16482,16483,
9400716484,16485,16486,16487,16488,16489,16490,16491,16492,16493,16494,16495,
9400816496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507,
9400916508,16509,16510,16511,16512,16513,16514,16515,16516,16517,16518,16519,
9401016520,16521,16522,16523,16524,16525,16526,16527,16528,16529,16530,16531,
9401116532,16533,16534,16535,16536,16537,16538,16539,16540,16541,16542,16543,
9401216544,16545,16546,16547,16548,16549,16550,16551,16552,16553,16554,16555,
9401316556,16557,16558,16559,16560,16561,16562,16563,16564,16565,16566,16567,
9401416568,16569,16570,16571,16572,16573,16574,16575,16576,16577,16578,16579,
9401516580,16581,16582,16583,16584,16585,16586,16587,16588,16589,16590,16591,
9401616592,16593,16594,16595,16596,16597,16598,16599,16600,16601,16602,16603,
9401716604,16605,16606,16607,16608,16609,16610,16611,16612,16613,16614,16615,
9401816616,16617,16618,16619,16620,16621,16622,16623,16624,16625,16626,16627,
9401916628,16629,16630,16631,16632,16633,16634,16635,16636,16637,16638,16639,
9402016640,16641,16642,16643,16644,16645,16646,16647,16648,16649,16650,16651,
9402116652,16653,16654,16655,16656,16657,16658,16659,16660,16661,16662,16663,
9402216664,16665,16666,16667,16668,16669,16670,16671,16672,16673,16674,16675,
9402316676,16677,16678,16679,16680,16681,16682,16683,16684,16685,16686,16687,
9402416688,16689,16690,16691,16692,16693,16694,16695,16696,16697,16698,16699,
9402516700,16701,16702,16703,16704,16705,16706,16707,16708,16709,16710,16711,
9402616712,16713,16714,16715,16716,16717,16718,16719,16720,16721,16722,16723,
9402716724,16725,16726,16727,16728,16729,16730,16731,16732,16733,16734,16735,
9402816736,16737,16738,16739,16740,16741,16742,16743,16744,16745,16746,16747,
9402916748,16749,16750,16751,16752,16753,16754,16755,16756,16757,16758,16759,
9403016760,16761,16762,16763,16764,16765,16766,16767,16768,16769,16770,16771,
9403116772,16773,16774,16775,16776,16777,16778,16779,16780,16781,16782,16783,
9403216784,16785,16786,16787,16788,16789,16790,16791,16792,16793,16794,16795,
9403316796,16797,16798,16799,16800,16801,16802,16803,16804,16805,16806,16807,
9403416808,16809,16810,16811,16812,16813,16814,16815,16816,16817,16818,16819,
9403516820,16821,16822,16823,16824,16825,16826,16827,16828,16829,16830,16831,
9403616832,16833,16834,16835,16836,16837,16838,16839,16840,16841,16842,16843,
9403716844,16845,16846,16847,16848,16849,16850,16851,16852,16853,16854,16855,
9403816856,16857,16858,16859,16860,16861,16862,16863,16864,16865,16866,16867,
9403916868,16869,16870,16871,16872,16873,16874,16875,16876,16877,16878,16879,
9404016880,16881,16882,16883,16884,16885,16886,16887,16888,16889,16890,16891,
9404116892,16893,16894,16895,16896,16897,16898,16899,16900,16901,16902,16903,
9404216904,16905,16906,16907,16908,16909,16910,16911,16912,16913,16914,16915,
9404316916,16917,16918,16919,16920,16921,16922,16923,16924,16925,16926,16927,
9404416928,16929,16930,16931,16932,16933,16934,16935,16936,16937,16938,16939,
9404516940,16941,16942,16943,16944,16945,16946,16947,16948,16949,16950,16951,
9404616952,16953,16954,16955,16956,16957,16958,16959,16960,16961,16962,16963,
9404716964,16965,16966,16967,16968,16969,16970,16971,16972,16973,16974,16975,
9404816976,16977,16978,16979,16980,16981,16982,16983,16984,16985,16986,16987,
9404916988,16989,16990,16991,16992,16993,16994,16995,16996,16997,16998,16999,
9405017000,17001,17002,17003,17004,17005,17006,17007,17008,17009,17010,17011,
9405117012,17013,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023,
9405217024,17025,17026,17027,17028,17029,17030,17031,17032,17033,17034,17035,
9405317036,17037,17038,17039,17040,17041,17042,17043,17044,17045,17046,17047,
9405417048,17049,17050,17051,17052,17053,17054,17055,17056,17057,17058,17059,
9405517060,17061,17062,17063,17064,17065,17066,17067,17068,17069,17070,17071,
9405617072,17073,17074,17075,17076,17077,17078,17079,17080,17081,17082,17083,
9405717084,17085,17086,17087,17088,17089,17090,17091,17092,17093,17094,17095,
9405817096,17097,17098,17099,17100,17101,17102,17103,17104,17105,17106,17107,
9405917108,17109,17110,17111,17112,17113,17114,17115,17116,17117,17118,17119,
9406017120,17121,17122,17123,17124,17125,17126,17127,17128,17129,17130,17131,
9406117132,17133,17134,17135,17136,17137,17138,17139,17140,17141,17142,17143,
9406217144,17145,17146,17147,17148,17149,17150,17151,17152,17153,17154,17155,
9406317156,17157,17158,17159,17160,17161,17162,17163,17164,17165,17166,17167,
9406417168,17169,17170,17171,17172,17173,17174,17175,17176,17177,17178,17179,
9406517180,17181,17182,17183,17184,17185,17186,17187,17188,17189,17190,17191,
9406617192,17193,17194,17195,17196,17197,17198,17199,17200,17201,17202,17203,
9406717204,17205,17206,17207,17208,17209,17210,17211,17212,17213,17214,17215,
9406817216,17217,17218,17219,17220,17221,17222,17223,17224,17225,17226,17227,
9406917228,17229,17230,17231,17232,17233,17234,17235,17236,17237,17238,17239,
9407017240,17241,17242,17243,17244,17245,17246,17247,17248,17249,17250,17251,
9407117252,17253,17254,17255,17256,17257,17258,17259,17260,17261,17262,17263,
9407217264,17265,17266,17267,17268,17269,17270,17271,17272,17273,17274,17275,
9407317276,17277,17278,17279,17280,17281,17282,17283,17284,17285,17286,17287,
9407417288,17289,17290,17291,17292,17293,17294,17295,17296,17297,17298,17299,
9407517300,17301,17302,17303,17304,17305,17306,17307,17308,17309,17310,17311,
9407617312,17313,17314,17315,17316,17317,17318,17319,17320,17321,17322,17323,
9407717324,17325,17326,17327,17328,17329,17330,17331,17332,17333,17334,17335,
9407817336,17337,17338,17339,17340,17341,17342,17343,17344,17345,17346,17347,
9407917348,17349,17350,17351,17352,17353,17354,17355,17356,17357,17358,17359,
9408017360,17361,17362,17363,17364,17365,17366,17367,17368,17369,17370,17371,
9408117372,17373,17374,17375,17376,17377,17378,17379,17380,17381,17382,17383,
9408217384,17385,17386,17387,17388,17389,17390,17391,17392,17393,17394,17395,
9408317396,17397,17398,17399,17400,17401,17402,17403,17404,17405,17406,17407,
9408417408,17409,17410,17411,17412,17413,17414,17415,17416,17417,17418,17419,
9408517420,17421,17422,17423,17424,17425,17426,17427,17428,17429,17430,17431,
9408617432,17433,17434,17435,17436,17437,17438,17439,17440,17441,17442,17443,
9408717444,17445,17446,17447,17448,17449,17450,17451,17452,17453,17454,17455,
9408817456,17457,17458,17459,17460,17461,17462,17463,17464,17465,17466,17467,
9408917468,17469,17470,17471,17472,17473,17474,17475,17476,17477,17478,17479,
9409017480,17481,17482,17483,17484,17485,17486,17487,17488,17489,17490,17491,
9409117492,17493,17494,17495,17496,17497,17498,17499,17500,17501,17502,17503,
9409217504,17505,17506,17507,17508,17509,17510,17511,17512,17513,17514,17515,
9409317516,17517,17518,17519,17520,17521,17522,17523,17524,17525,17526,17527,
9409417528,17529,17530,17531,17532,17533,17534,17535,17536,17537,17538,17539,
9409517540,17541,17542,17543,17544,17545,17546,17547,17548,17549,17550,17551,
9409617552,17553,17554,17555,17556,17557,17558,17559,17560,17561,17562,17563,
9409717564,17565,17566,17567,17568,17569,17570,17571,17572,17573,17574,17575,
9409817576,17577,17578,17579,17580,17581,17582,17583,17584,17585,17586,17587,
9409917588,17589,17590,17591,17592,17593,17594,17595,17596,17597,17598,17599,
9410017600,17601,17602,17603,17604,17605,17606,17607,17608,17609,17610,17611,
9410117612,17613,17614,17615,17616,17617,17618,17619,17620,17621,17622,17623,
9410217624,17625,17626,17627,17628,17629,17630,17631,17632,17633,17634,17635,
9410317636,17637,17638,17639,17640,17641,17642,17643,17644,17645,17646,17647,
9410417648,17649,17650,17651,17652,17653,17654,17655,17656,17657,17658,17659,
9410517660,17661,17662,17663,17664,17665,17666,17667,17668,17669,17670,17671,
9410617672,17673,17674,17675,17676,17677,17678,17679,17680,17681,17682,17683,
9410717684,17685,17686,17687,17688,17689,17690,17691,17692,17693,17694,17695,
9410817696,17697,17698,17699,17700,17701,17702,17703,17704,17705,17706,17707,
9410917708,17709,17710,17711,17712,17713,17714,17715,17716,17717,17718,17719,
9411017720,17721,17722,17723,17724,17725,17726,17727,17728,17729,17730,17731,
9411117732,17733,17734,17735,17736,17737,17738,17739,17740,17741,17742,17743,
9411217744,17745,17746,17747,17748,17749,17750,17751,17752,17753,17754,17755,
9411317756,17757,17758,17759,17760,17761,17762,17763,17764,17765,17766,17767,
9411417768,17769,17770,17771,17772,17773,17774,17775,17776,17777,17778,17779,
9411517780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791,
9411617792,17793,17794,17795,17796,17797,17798,17799,17800,17801,17802,17803,
9411717804,17805,17806,17807,17808,17809,17810,17811,17812,17813,17814,17815,
9411817816,17817,17818,17819,17820,17821,17822,17823,17824,17825,17826,17827,
9411917828,17829,17830,17831,17832,17833,17834,17835,17836,17837,17838,17839,
9412017840,17841,17842,17843,17844,17845,17846,17847,17848,17849,17850,17851,
9412117852,17853,17854,17855,17856,17857,17858,17859,17860,17861,17862,17863,
9412217864,17865,17866,17867,17868,17869,17870,17871,17872,17873,17874,17875,
9412317876,17877,17878,17879,17880,17881,17882,17883,17884,17885,17886,17887,
9412417888,17889,17890,17891,17892,17893,17894,17895,17896,17897,17898,17899,
9412517900,17901,17902,17903,17904,17905,17906,17907,17908,17909,17910,17911,
9412617912,17913,17914,17915,17916,17917,17918,17919,17920,17921,17922,17923,
9412717924,17925,17926,17927,17928,17929,17930,17931,17932,17933,17934,17935,
9412817936,17937,17938,17939,17940,17941,17942,17943,17944,17945,17946,17947,
9412917948,17949,17950,17951,17952,17953,17954,17955,17956,17957,17958,17959,
9413017960,17961,17962,17963,17964,17965,17966,17967,17968,17969,17970,17971,
9413117972,17973,17974,17975,17976,17977,17978,17979,17980,17981,17982,17983,
9413217984,17985,17986,17987,17988,17989,17990,17991,17992,17993,17994,17995,
9413317996,17997,17998,17999,18000,18001,18002,18003,18004,18005,18006,18007,
9413418008,18009,18010,18011,18012,18013,18014,18015,18016,18017,18018,18019,
9413518020,18021,18022,18023,18024,18025,18026,18027,18028,18029,18030,18031,
9413618032,18033,18034,18035,18036,18037,18038,18039,18040,18041,18042,18043,
9413718044,18045,18046,18047,18048,18049,18050,18051,18052,18053,18054,18055,
9413818056,18057,18058,18059,18060,18061,18062,18063,18064,18065,18066,18067,
9413918068,18069,18070,18071,18072,18073,18074,18075,18076,18077,18078,18079,
9414018080,18081,18082,18083,18084,18085,18086,18087,18088,18089,18090,18091,
9414118092,18093,18094,18095,18096,18097,18098,18099,18100,18101,18102,18103,
9414218104,18105,18106,18107,18108,18109,18110,18111,18112,18113,18114,18115,
9414318116,18117,18118,18119,18120,18121,18122,18123,18124,18125,18126,18127,
9414418128,18129,18130,18131,18132,18133,18134,18135,18136,18137,18138,18139,
9414518140,18141,18142,18143,18144,18145,18146,18147,18148,18149,18150,18151,
9414618152,18153,18154,18155,18156,18157,18158,18159,18160,18161,18162,18163,
9414718164,18165,18166,18167,18168,18169,18170,18171,18172,18173,18174,18175,
9414818176,18177,18178,18179,18180,18181,18182,18183,18184,18185,18186,18187,
9414918188,18189,18190,18191,18192,18193,18194,18195,18196,18197,18198,18199,
9415018200,18201,18202,18203,18204,18205,18206,18207,18208,18209,18210,18211,
9415118212,18213,18214,18215,18216,18217,18218,18219,18220,18221,18222,18223,
9415218224,18225,18226,18227,18228,18229,18230,18231,18232,18233,18234,18235,
9415318236,18237,18238,18239,18240,18241,18242,18243,18244,18245,18246,18247,
9415418248,18249,18250,18251,18252,18253,18254,18255,18256,18257,18258,18259,
9415518260,18261,18262,18263,18264,18265,18266,18267,18268,18269,18270,18271,
9415618272,18273,18274,18275,18276,18277,18278,18279,18280,18281,18282,18283,
9415718284,18285,18286,18287,18288,18289,18290,18291,18292,18293,18294,18295,
9415818296,18297,18298,18299,18300,18301,18302,18303,18304,18305,18306,18307,
9415918308,18309,18310,18311,18312,18313,18314,18315,18316,18317,18318,18319,
9416018320,18321,18322,18323,18324,18325,18326,18327,18328,18329,18330,18331,
9416118332,18333,18334,18335,18336,18337,18338,18339,18340,18341,18342,18343,
9416218344,18345,18346,18347,18348,18349,18350,18351,18352,18353,18354,18355,
9416318356,18357,18358,18359,18360,18361,18362,18363,18364,18365,18366,18367,
9416418368,18369,18370,18371,18372,18373,18374,18375,18376,18377,18378,18379,
9416518380,18381,18382,18383,18384,18385,18386,18387,18388,18389,18390,18391,
9416618392,18393,18394,18395,18396,18397,18398,18399,18400,18401,18402,18403,
9416718404,18405,18406,18407,18408,18409,18410,18411,18412,18413,18414,18415,
9416818416,18417,18418,18419,18420,18421,18422,18423,18424,18425,18426,18427,
9416918428,18429,18430,18431,18432,18433,18434,18435,18436,18437,18438,18439,
9417018440,18441,18442,18443,18444,18445,18446,18447,18448,18449,18450,18451,
9417118452,18453,18454,18455,18456,18457,18458,18459,18460,18461,18462,18463,
9417218464,18465,18466,18467,18468,18469,18470,18471,18472,18473,18474,18475,
9417318476,18477,18478,18479,18480,18481,18482,18483,18484,18485,18486,18487,
9417418488,18489,18490,18491,18492,18493,18494,18495,18496,18497,18498,18499,
9417518500,18501,18502,18503,18504,18505,18506,18507,18508,18509,18510,18511,
9417618512,18513,18514,18515,18516,18517,18518,18519,18520,18521,18522,18523,
9417718524,18525,18526,18527,18528,18529,18530,18531,18532,18533,18534,18535,
9417818536,18537,18538,18539,18540,18541,18542,18543,18544,18545,18546,18547,
9417918548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559,
9418018560,18561,18562,18563,18564,18565,18566,18567,18568,18569,18570,18571,
9418118572,18573,18574,18575,18576,18577,18578,18579,18580,18581,18582,18583,
9418218584,18585,18586,18587,18588,18589,18590,18591,18592,18593,18594,18595,
9418318596,18597,18598,18599,18600,18601,18602,18603,18604,18605,18606,18607,
9418418608,18609,18610,18611,18612,18613,18614,18615,18616,18617,18618,18619,
9418518620,18621,18622,18623,18624,18625,18626,18627,18628,18629,18630,18631,
9418618632,18633,18634,18635,18636,18637,18638,18639,18640,18641,18642,18643,
9418718644,18645,18646,18647,18648,18649,18650,18651,18652,18653,18654,18655,
9418818656,18657,18658,18659,18660,18661,18662,18663,18664,18665,18666,18667,
9418918668,18669,18670,18671,18672,18673,18674,18675,18676,18677,18678,18679,
9419018680,18681,18682,18683,18684,18685,18686,18687,18688,18689,18690,18691,
9419118692,18693,18694,18695,18696,18697,18698,18699,18700,18701,18702,18703,
9419218704,18705,18706,18707,18708,18709,18710,18711,18712,18713,18714,18715,
9419318716,18717,18718,18719,18720,18721,18722,18723,18724,18725,18726,18727,
9419418728,18729,18730,18731,18732,18733,18734,18735,18736,18737,18738,18739,
9419518740,18741,18742,18743,18744,18745,18746,18747,18748,18749,18750,18751,
9419618752,18753,18754,18755,18756,18757,18758,18759,18760,18761,18762,18763,
9419718764,18765,18766,18767,18768,18769,18770,18771,18772,18773,18774,18775,
9419818776,18777,18778,18779,18780,18781,18782,18783,18784,18785,18786,18787,
9419918788,18789,18790,18791,18792,18793,18794,18795,18796,18797,18798,18799,
9420018800,18801,18802,18803,18804,18805,18806,18807,18808,18809,18810,18811,
9420118812,18813,18814,18815,18816,18817,18818,18819,18820,18821,18822,18823,
9420218824,18825,18826,18827,18828,18829,18830,18831,18832,18833,18834,18835,
9420318836,18837,18838,18839,18840,18841,18842,18843,18844,18845,18846,18847,
9420418848,18849,18850,18851,18852,18853,18854,18855,18856,18857,18858,18859,
9420518860,18861,18862,18863,18864,18865,18866,18867,18868,18869,18870,18871,
9420618872,18873,18874,18875,18876,18877,18878,18879,18880,18881,18882,18883,
9420718884,18885,18886,18887,18888,18889,18890,18891,18892,18893,18894,18895,
9420818896,18897,18898,18899,18900,18901,18902,18903,18904,18905,18906,18907,
9420918908,18909,18910,18911,18912,18913,18914,18915,18916,18917,18918,18919,
9421018920,18921,18922,18923,18924,18925,18926,18927,18928,18929,18930,18931,
9421118932,18933,18934,18935,18936,18937,18938,18939,18940,18941,18942,18943,
9421218944,18945,18946,18947,18948,18949,18950,18951,18952,18953,18954,18955,
9421318956,18957,18958,18959,18960,18961,18962,18963,18964,18965,18966,18967,
9421418968,18969,18970,18971,18972,18973,18974,18975,18976,18977,18978,18979,
9421518980,18981,18982,18983,18984,18985,18986,18987,18988,18989,18990,18991,
9421618992,18993,18994,18995,18996,18997,18998,18999,19000,19001,19002,19003,
9421719004,19005,19006,19007,19008,19009,19010,19011,19012,19013,19014,19015,
9421819016,19017,19018,19019,19020,19021,19022,19023,19024,19025,19026,19027,
9421919028,19029,19030,19031,19032,19033,19034,19035,19036,19037,19038,19039,
9422019040,19041,19042,19043,19044,19045,19046,19047,19048,19049,19050,19051,
9422119052,19053,19054,19055,19056,19057,19058,19059,19060,19061,19062,19063,
9422219064,19065,19066,19067,19068,19069,19070,19071,19072,19073,19074,19075,
9422319076,19077,19078,19079,19080,19081,19082,19083,19084,19085,19086,19087,
9422419088,19089,19090,19091,19092,19093,19094,19095,19096,19097,19098,19099,
9422519100,19101,19102,19103,19104,19105,19106,19107,19108,19109,19110,19111,
9422619112,19113,19114,19115,19116,19117,19118,19119,19120,19121,19122,19123,
9422719124,19125,19126,19127,19128,19129,19130,19131,19132,19133,19134,19135,
9422819136,19137,19138,19139,19140,19141,19142,19143,19144,19145,19146,19147,
9422919148,19149,19150,19151,19152,19153,19154,19155,19156,19157,19158,19159,
9423019160,19161,19162,19163,19164,19165,19166,19167,19168,19169,19170,19171,
9423119172,19173,19174,19175,19176,19177,19178,19179,19180,19181,19182,19183,
9423219184,19185,19186,19187,19188,19189,19190,19191,19192,19193,19194,19195,
9423319196,19197,19198,19199,19200,19201,19202,19203,19204,19205,19206,19207,
9423419208,19209,19210,19211,19212,19213,19214,19215,19216,19217,19218,19219,
9423519220,19221,19222,19223,19224,19225,19226,19227,19228,19229,19230,19231,
9423619232,19233,19234,19235,19236,19237,19238,19239,19240,19241,19242,19243,
9423719244,19245,19246,19247,19248,19249,19250,19251,19252,19253,19254,19255,
9423819256,19257,19258,19259,19260,19261,19262,19263,19264,19265,19266,19267,
9423919268,19269,19270,19271,19272,19273,19274,19275,19276,19277,19278,19279,
9424019280,19281,19282,19283,19284,19285,19286,19287,19288,19289,19290,19291,
9424119292,19293,19294,19295,19296,19297,19298,19299,19300,19301,19302,19303,
9424219304,19305,19306,19307,19308,19309,19310,19311,19312,19313,19314,19315,
9424319316,19317,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327,
9424419328,19329,19330,19331,19332,19333,19334,19335,19336,19337,19338,19339,
9424519340,19341,19342,19343,19344,19345,19346,19347,19348,19349,19350,19351,
9424619352,19353,19354,19355,19356,19357,19358,19359,19360,19361,19362,19363,
9424719364,19365,19366,19367,19368,19369,19370,19371,19372,19373,19374,19375,
9424819376,19377,19378,19379,19380,19381,19382,19383,19384,19385,19386,19387,
9424919388,19389,19390,19391,19392,19393,19394,19395,19396,19397,19398,19399,
9425019400,19401,19402,19403,19404,19405,19406,19407,19408,19409,19410,19411,
9425119412,19413,19414,19415,19416,19417,19418,19419,19420,19421,19422,19423,
9425219424,19425,19426,19427,19428,19429,19430,19431,19432,19433,19434,19435,
9425319436,19437,19438,19439,19440,19441,19442,19443,19444,19445,19446,19447,
9425419448,19449,19450,19451,19452,19453,19454,19455,19456,19457,19458,19459,
9425519460,19461,19462,19463,19464,19465,19466,19467,19468,19469,19470,19471,
9425619472,19473,19474,19475,19476,19477,19478,19479,19480,19481,19482,19483,
9425719484,19485,19486,19487,19488,19489,19490,19491,19492,19493,19494,19495,
9425819496,19497,19498,19499,19500,19501,19502,19503,19504,19505,19506,19507,
9425919508,19509,19510,19511,19512,19513,19514,19515,19516,19517,19518,19519,
9426019520,19521,19522,19523,19524,19525,19526,19527,19528,19529,19530,19531,
9426119532,19533,19534,19535,19536,19537,19538,19539,19540,19541,19542,19543,
9426219544,19545,19546,19547,19548,19549,19550,19551,19552,19553,19554,19555,
9426319556,19557,19558,19559,19560,19561,19562,19563,19564,19565,19566,19567,
9426419568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579,
9426519580,19581,19582,19583,19584,19585,19586,19587,19588,19589,19590,19591,
9426619592,19593,19594,19595,19596,19597,19598,19599,19600,19601,19602,19603,
9426719604,19605,19606,19607,19608,19609,19610,19611,19612,19613,19614,19615,
9426819616,19617,19618,19619,19620,19621,19622,19623,19624,19625,19626,19627,
9426919628,19629,19630,19631,19632,19633,19634,19635,19636,19637,19638,19639,
9427019640,19641,19642,19643,19644,19645,19646,19647,19648,19649,19650,19651,
9427119652,19653,19654,19655,19656,19657,19658,19659,19660,19661,19662,19663,
9427219664,19665,19666,19667,19668,19669,19670,19671,19672,19673,19674,19675,
9427319676,19677,19678,19679,19680,19681,19682,19683,19684,19685,19686,19687,
9427419688,19689,19690,19691,19692,19693,19694,19695,19696,19697,19698,19699,
9427519700,19701,19702,19703,19704,19705,19706,19707,19708,19709,19710,19711,
9427619712,19713,19714,19715,19716,19717,19718,19719,19720,19721,19722,19723,
9427719724,19725,19726,19727,19728,19729,19730,19731,19732,19733,19734,19735,
9427819736,19737,19738,19739,19740,19741,19742,19743,19744,19745,19746,19747,
9427919748,19749,19750,19751,19752,19753,19754,19755,19756,19757,19758,19759,
9428019760,19761,19762,19763,19764,19765,19766,19767,19768,19769,19770,19771,
9428119772,19773,19774,19775,19776,19777,19778,19779,19780,19781,19782,19783,
9428219784,19785,19786,19787,19788,19789,19790,19791,19792,19793,19794,19795,
9428319796,19797,19798,19799,19800,19801,19802,19803,19804,19805,19806,19807,
9428419808,19809,19810,19811,19812,19813,19814,19815,19816,19817,19818,19819,
9428519820,19821,19822,19823,19824,19825,19826,19827,19828,19829,19830,19831,
9428619832,19833,19834,19835,19836,19837,19838,19839,19840,19841,19842,19843,
9428719844,19845,19846,19847,19848,19849,19850,19851,19852,19853,19854,19855,
9428819856,19857,19858,19859,19860,19861,19862,19863,19864,19865,19866,19867,
9428919868,19869,19870,19871,19872,19873,19874,19875,19876,19877,19878,19879,
9429019880,19881,19882,19883,19884,19885,19886,19887,19888,19889,19890,19891,
9429119892,19893,19894,19895,19896,19897,19898,19899,19900,19901,19902,19903,
9429219904,19905,19906,19907,19908,19909,19910,19911,19912,19913,19914,19915,
9429319916,19917,19918,19919,19920,19921,19922,19923,19924,19925,19926,19927,
9429419928,19929,19930,19931,19932,19933,19934,19935,19936,19937,19938,19939,
9429519940,19941,19942,19943,19944,19945,19946,19947,19948,19949,19950,19951,
9429619952,19953,19954,19955,19956,19957,19958,19959,19960,19961,19962,19963,
9429719964,19965,19966,19967,19968,19969,19970,19971,19972,19973,19974,19975,
9429819976,19977,19978,19979,19980,19981,19982,19983,19984,19985,19986,19987,
9429919988,19989,19990,19991,19992,19993,19994,19995,19996,19997,19998,19999,
9430020000,20001,20002,20003,20004,20005,20006,20007,20008,20009,20010,20011,
9430120012,20013,20014,20015,20016,20017,20018,20019,20020,20021,20022,20023,
9430220024,20025,20026,20027,20028,20029,20030,20031,20032,20033,20034,20035,
9430320036,20037,20038,20039,20040,20041,20042,20043,20044,20045,20046,20047,
9430420048,20049,20050,20051,20052,20053,20054,20055,20056,20057,20058,20059,
9430520060,20061,20062,20063,20064,20065,20066,20067,20068,20069,20070,20071,
9430620072,20073,20074,20075,20076,20077,20078,20079,20080,20081,20082,20083,
9430720084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20094,20095,
9430820096,20097,20098,20099,20100,20101,20102,20103,20104,20105,20106,20107,
9430920108,20109,20110,20111,20112,20113,20114,20115,20116,20117,20118,20119,
9431020120,20121,20122,20123,20124,20125,20126,20127,20128,20129,20130,20131,
9431120132,20133,20134,20135,20136,20137,20138,20139,20140,20141,20142,20143,
9431220144,20145,20146,20147,20148,20149,20150,20151,20152,20153,20154,20155,
9431320156,20157,20158,20159,20160,20161,20162,20163,20164,20165,20166,20167,
9431420168,20169,20170,20171,20172,20173,20174,20175,20176,20177,20178,20179,
9431520180,20181,20182,20183,20184,20185,20186,20187,20188,20189,20190,20191,
9431620192,20193,20194,20195,20196,20197,20198,20199,20200,20201,20202,20203,
9431720204,20205,20206,20207,20208,20209,20210,20211,20212,20213,20214,20215,
9431820216,20217,20218,20219,20220,20221,20222,20223,20224,20225,20226,20227,
9431920228,20229,20230,20231,20232,20233,20234,20235,20236,20237,20238,20239,
9432020240,20241,20242,20243,20244,20245,20246,20247,20248,20249,20250,20251,
9432120252,20253,20254,20255,20256,20257,20258,20259,20260,20261,20262,20263,
9432220264,20265,20266,20267,20268,20269,20270,20271,20272,20273,20274,20275,
9432320276,20277,20278,20279,20280,20281,20282,20283,20284,20285,20286,20287,
9432420288,20289,20290,20291,20292,20293,20294,20295,20296,20297,20298,20299,
9432520300,20301,20302,20303,20304,20305,20306,20307,20308,20309,20310,20311,
9432620312,20313,20314,20315,20316,20317,20318,20319,20320,20321,20322,20323,
9432720324,20325,20326,20327,20328,20329,20330,20331,20332,20333,20334,20335,
9432820336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347,
9432920348,20349,20350,20351,20352,20353,20354,20355,20356,20357,20358,20359,
9433020360,20361,20362,20363,20364,20365,20366,20367,20368,20369,20370,20371,
9433120372,20373,20374,20375,20376,20377,20378,20379,20380,20381,20382,20383,
9433220384,20385,20386,20387,20388,20389,20390,20391,20392,20393,20394,20395,
9433320396,20397,20398,20399,20400,20401,20402,20403,20404,20405,20406,20407,
9433420408,20409,20410,20411,20412,20413,20414,20415,20416,20417,20418,20419,
9433520420,20421,20422,20423,20424,20425,20426,20427,20428,20429,20430,20431,
9433620432,20433,20434,20435,20436,20437,20438,20439,20440,20441,20442,20443,
9433720444,20445,20446,20447,20448,20449,20450,20451,20452,20453,20454,20455,
9433820456,20457,20458,20459,20460,20461,20462,20463,20464,20465,20466,20467,
9433920468,20469,20470,20471,20472,20473,20474,20475,20476,20477,20478,20479,
9434020480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,
9434120492,20493,20494,20495,20496,20497,20498,20499,20500,20501,20502,20503,
9434220504,20505,20506,20507,20508,20509,20510,20511,20512,20513,20514,20515,
9434320516,20517,20518,20519,20520,20521,20522,20523,20524,20525,20526,20527,
9434420528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20538,20539,
9434520540,20541,20542,20543,20544,20545,20546,20547,20548,20549,20550,20551,
9434620552,20553,20554,20555,20556,20557,20558,20559,20560,20561,20562,20563,
9434720564,20565,20566,20567,20568,20569,20570,20571,20572,20573,20574,20575,
9434820576,20577,20578,20579,20580,20581,20582,20583,20584,20585,20586,20587,
9434920588,20589,20590,20591,20592,20593,20594,20595,20596,20597,20598,20599,
9435020600,20601,20602,20603,20604,20605,20606,20607,20608,20609,20610,20611,
9435120612,20613,20614,20615,20616,20617,20618,20619,20620,20621,20622,20623,
9435220624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,
9435320636,20637,20638,20639,20640,20641,20642,20643,20644,20645,20646,20647,
9435420648,20649,20650,20651,20652,20653,20654,20655,20656,20657,20658,20659,
9435520660,20661,20662,20663,20664,20665,20666,20667,20668,20669,20670,20671,
9435620672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,
9435720684,20685,20686,20687,20688,20689,20690,20691,20692,20693,20694,20695,
9435820696,20697,20698,20699,20700,20701,20702,20703,20704,20705,20706,20707,
9435920708,20709,20710,20711,20712,20713,20714,20715,20716,20717,20718,20719,
9436020720,20721,20722,20723,20724,20725,20726,20727,20728,20729,20730,20731,
9436120732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20742,20743,
9436220744,20745,20746,20747,20748,20749,20750,20751,20752,20753,20754,20755,
9436320756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,
9436420768,20769,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,
9436520780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,
9436620792,20793,20794,20795,20796,20797,20798,20799,20800,20801,20802,20803,
9436720804,20805,20806,20807,20808,20809,20810,20811,20812,20813,20814,20815,
9436820816,20817,20818,20819,20820,20821,20822,20823,20824,20825,20826,20827,
9436920828,20829,20830,20831,20832,20833,20834,20835,20836,20837,20838,20839,
9437020840,20841,20842,20843,20844,20845,20846,20847,20848,20849,20850,20851,
9437120852,20853,20854,20855,20856,20857,20858,20859,20860,20861,20862,20863,
9437220864,20865,20866,20867,20868,20869,20870,20871,20872,20873,20874,20875,
9437320876,20877,20878,20879,20880,20881,20882,20883,20884,20885,20886,20887,
9437420888,20889,20890,20891,20892,20893,20894,20895,20896,20897,20898,20899,
9437520900,20901,20902,20903,20904,20905,20906,20907,20908,20909,20910,20911,
9437620912,20913,20914,20915,20916,20917,20918,20919,20920,20921,20922,20923,
9437720924,20925,20926,20927,20928,20929,20930,20931,20932,20933,20934,20935,
9437820936,20937,20938,20939,20940,20941,20942,20943,20944,20945,20946,20947,
9437920948,20949,20950,20951,20952,20953,20954,20955,20956,20957,20958,20959,
9438020960,20961,20962,20963,20964,20965,20966,20967,20968,20969,20970,20971,
9438120972,20973,20974,20975,20976,20977,20978,20979,20980,20981,20982,20983,
9438220984,20985,20986,20987,20988,20989,20990,20991,20992,20993,20994,20995,
9438320996,20997,20998,20999,21000,21001,21002,21003,21004,21005,21006,21007,
9438421008,21009,21010,21011,21012,21013,21014,21015,21016,21017,21018,21019,
9438521020,21021,21022,21023,21024,21025,21026,21027,21028,21029,21030,21031,
9438621032,21033,21034,21035,21036,21037,21038,21039,21040,21041,21042,21043,
9438721044,21045,21046,21047,21048,21049,21050,21051,21052,21053,21054,21055,
9438821056,21057,21058,21059,21060,21061,21062,21063,21064,21065,21066,21067,
9438921068,21069,21070,21071,21072,21073,21074,21075,21076,21077,21078,21079,
9439021080,21081,21082,21083,21084,21085,21086,21087,21088,21089,21090,21091,
9439121092,21093,21094,21095,21096,21097,21098,21099,21100,21101,21102,21103,
9439221104,21105,21106,21107,21108,21109,21110,21111,21112,21113,21114,21115,
9439321116,21117,21118,21119,21120,21121,21122,21123,21124,21125,21126,21127,
9439421128,21129,21130,21131,21132,21133,21134,21135,21136,21137,21138,21139,
9439521140,21141,21142,21143,21144,21145,21146,21147,21148,21149,21150,21151,
9439621152,21153,21154,21155,21156,21157,21158,21159,21160,21161,21162,21163,
9439721164,21165,21166,21167,21168,21169,21170,21171,21172,21173,21174,21175,
9439821176,21177,21178,21179,21180,21181,21182,21183,21184,21185,21186,21187,
9439921188,21189,21190,21191,21192,21193,21194,21195,21196,21197,21198,21199,
9440021200,21201,21202,21203,21204,21205,21206,21207,21208,21209,21210,21211,
9440121212,21213,21214,21215,21216,21217,21218,21219,21220,21221,21222,21223,
9440221224,21225,21226,21227,21228,21229,21230,21231,21232,21233,21234,21235,
9440321236,21237,21238,21239,21240,21241,21242,21243,21244,21245,21246,21247,
9440421248,21249,21250,21251,21252,21253,21254,21255,21256,21257,21258,21259,
9440521260,21261,21262,21263,21264,21265,21266,21267,21268,21269,21270,21271,
9440621272,21273,21274,21275,21276,21277,21278,21279,21280,21281,21282,21283,
9440721284,21285,21286,21287,21288,21289,21290,21291,21292,21293,21294,21295,
9440821296,21297,21298,21299,21300,21301,21302,21303,21304,21305,21306,21307,
9440921308,21309,21310,21311,21312,21313,21314,21315,21316,21317,21318,21319,
9441021320,21321,21322,21323,21324,21325,21326,21327,21328,21329,21330,21331,
9441121332,21333,21334,21335,21336,21337,21338,21339,21340,21341,21342,21343,
9441221344,21345,21346,21347,21348,21349,21350,21351,21352,21353,21354,21355,
9441321356,21357,21358,21359,21360,21361,21362,21363,21364,21365,21366,21367,
9441421368,21369,21370,21371,21372,21373,21374,21375,21376,21377,21378,21379,
9441521380,21381,21382,21383,21384,21385,21386,21387,21388,21389,21390,21391,
9441621392,21393,21394,21395,21396,21397,21398,21399,21400,21401,21402,21403,
9441721404,21405,21406,21407,21408,21409,21410,21411,21412,21413,21414,21415,
9441821416,21417,21418,21419,21420,21421,21422,21423,21424,21425,21426,21427,
9441921428,21429,21430,21431,21432,21433,21434,21435,21436,21437,21438,21439,
9442021440,21441,21442,21443,21444,21445,21446,21447,21448,21449,21450,21451,
9442121452,21453,21454,21455,21456,21457,21458,21459,21460,21461,21462,21463,
9442221464,21465,21466,21467,21468,21469,21470,21471,21472,21473,21474,21475,
9442321476,21477,21478,21479,21480,21481,21482,21483,21484,21485,21486,21487,
9442421488,21489,21490,21491,21492,21493,21494,21495,21496,21497,21498,21499,
9442521500,21501,21502,21503,21504,21505,21506,21507,21508,21509,21510,21511,
9442621512,21513,21514,21515,21516,21517,21518,21519,21520,21521,21522,21523,
9442721524,21525,21526,21527,21528,21529,21530,21531,21532,21533,21534,21535,
9442821536,21537,21538,21539,21540,21541,21542,21543,21544,21545,21546,21547,
9442921548,21549,21550,21551,21552,21553,21554,21555,21556,21557,21558,21559,
9443021560,21561,21562,21563,21564,21565,21566,21567,21568,21569,21570,21571,
9443121572,21573,21574,21575,21576,21577,21578,21579,21580,21581,21582,21583,
9443221584,21585,21586,21587,21588,21589,21590,21591,21592,21593,21594,21595,
9443321596,21597,21598,21599,21600,21601,21602,21603,21604,21605,21606,21607,
9443421608,21609,21610,21611,21612,21613,21614,21615,21616,21617,21618,21619,
9443521620,21621,21622,21623,21624,21625,21626,21627,21628,21629,21630,21631,
9443621632,21633,21634,21635,21636,21637,21638,21639,21640,21641,21642,21643,
9443721644,21645,21646,21647,21648,21649,21650,21651,21652,21653,21654,21655,
9443821656,21657,21658,21659,21660,21661,21662,21663,21664,21665,21666,21667,
9443921668,21669,21670,21671,21672,21673,21674,21675,21676,21677,21678,21679,
9444021680,21681,21682,21683,21684,21685,21686,21687,21688,21689,21690,21691,
9444121692,21693,21694,21695,21696,21697,21698,21699,21700,21701,21702,21703,
9444221704,21705,21706,21707,21708,21709,21710,21711,21712,21713,21714,21715,
9444321716,21717,21718,21719,21720,21721,21722,21723,21724,21725,21726,21727,
9444421728,21729,21730,21731,21732,21733,21734,21735,21736,21737,21738,21739,
9444521740,21741,21742,21743,21744,21745,21746,21747,21748,21749,21750,21751,
9444621752,21753,21754,21755,21756,21757,21758,21759,21760,21761,21762,21763,
9444721764,21765,21766,21767,21768,21769,21770,21771,21772,21773,21774,21775,
9444821776,21777,21778,21779,21780,21781,21782,21783,21784,21785,21786,21787,
9444921788,21789,21790,21791,21792,21793,21794,21795,21796,21797,21798,21799,
9445021800,21801,21802,21803,21804,21805,21806,21807,21808,21809,21810,21811,
9445121812,21813,21814,21815,21816,21817,21818,21819,21820,21821,21822,21823,
9445221824,21825,21826,21827,21828,21829,21830,21831,21832,21833,21834,21835,
9445321836,21837,21838,21839,21840,21841,21842,21843,21844,21845,21846,21847,
9445421848,21849,21850,21851,21852,21853,21854,21855,21856,21857,21858,21859,
9445521860,21861,21862,21863,21864,21865,21866,21867,21868,21869,21870,21871,
9445621872,21873,21874,21875,21876,21877,21878,21879,21880,21881,21882,21883,
9445721884,21885,21886,21887,21888,21889,21890,21891,21892,21893,21894,21895,
9445821896,21897,21898,21899,21900,21901,21902,21903,21904,21905,21906,21907,
9445921908,21909,21910,21911,21912,21913,21914,21915,21916,21917,21918,21919,
9446021920,21921,21922,21923,21924,21925,21926,21927,21928,21929,21930,21931,
9446121932,21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,21943,
9446221944,21945,21946,21947,21948,21949,21950,21951,21952,21953,21954,21955,
9446321956,21957,21958,21959,21960,21961,21962,21963,21964,21965,21966,21967,
9446421968,21969,21970,21971,21972,21973,21974,21975,21976,21977,21978,21979,
9446521980,21981,21982,21983,21984,21985,21986,21987,21988,21989,21990,21991,
9446621992,21993,21994,21995,21996,21997,21998,21999,22000,22001,22002,22003,
9446722004,22005,22006,22007,22008,22009,22010,22011,22012,22013,22014,22015,
9446822016,22017,22018,22019,22020,22021,22022,22023,22024,22025,22026,22027,
9446922028,22029,22030,22031,22032,22033,22034,22035,22036,22037,22038,22039,
9447022040,22041,22042,22043,22044,22045,22046,22047,22048,22049,22050,22051,
9447122052,22053,22054,22055,22056,22057,22058,22059,22060,22061,22062,22063,
9447222064,22065,22066,22067,22068,22069,22070,22071,22072,22073,22074,22075,
9447322076,22077,22078,22079,22080,22081,22082,22083,22084,22085,22086,22087,
9447422088,22089,22090,22091,22092,22093,22094,22095,22096,22097,22098,22099,
9447522100,22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,22111,
9447622112,22113,22114,22115,22116,22117,22118,22119,22120,22121,22122,22123,
9447722124,22125,22126,22127,22128,22129,22130,22131,22132,22133,22134,22135,
9447822136,22137,22138,22139,22140,22141,22142,22143,22144,22145,22146,22147,
9447922148,22149,22150,22151,22152,22153,22154,22155,22156,22157,22158,22159,
9448022160,22161,22162,22163,22164,22165,22166,22167,22168,22169,22170,22171,
9448122172,22173,22174,22175,22176,22177,22178,22179,22180,22181,22182,22183,
9448222184,22185,22186,22187,22188,22189,22190,22191,22192,22193,22194,22195,
9448322196,22197,22198,22199,22200,22201,22202,22203,22204,22205,22206,22207,
9448422208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22218,22219,
9448522220,22221,22222,22223,22224,22225,22226,22227,22228,22229,22230,22231,
9448622232,22233,22234,22235,22236,22237,22238,22239,22240,22241,22242,22243,
9448722244,22245,22246,22247,22248,22249,22250,22251,22252,22253,22254,22255,
9448822256,22257,22258,22259,22260,22261,22262,22263,22264,22265,22266,22267,
9448922268,22269,22270,22271,22272,22273,22274,22275,22276,22277,22278,22279,
9449022280,22281,22282,22283,22284,22285,22286,22287,22288,22289,22290,22291,
9449122292,22293,22294,22295,22296,22297,22298,22299,22300,22301,22302,22303,
9449222304,22305,22306,22307,22308,22309,22310,22311,22312,22313,22314,22315,
9449322316,22317,22318,22319,22320,22321,22322,22323,22324,22325,22326,22327,
9449422328,22329,22330,22331,22332,22333,22334,22335,22336,22337,22338,22339,
9449522340,22341,22342,22343,22344,22345,22346,22347,22348,22349,22350,22351,
9449622352,22353,22354,22355,22356,22357,22358,22359,22360,22361,22362,22363,
9449722364,22365,22366,22367,22368,22369,22370,22371,22372,22373,22374,22375,
9449822376,22377,22378,22379,22380,22381,22382,22383,22384,22385,22386,22387,
9449922388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,22399,
9450022400,22401,22402,22403,22404,22405,22406,22407,22408,22409,22410,22411,
9450122412,22413,22414,22415,22416,22417,22418,22419,22420,22421,22422,22423,
9450222424,22425,22426,22427,22428,22429,22430,22431,22432,22433,22434,22435,
9450322436,22437,22438,22439,22440,22441,22442,22443,22444,22445,22446,22447,
9450422448,22449,22450,22451,22452,22453,22454,22455,22456,22457,22458,22459,
9450522460,22461,22462,22463,22464,22465,22466,22467,22468,22469,22470,22471,
9450622472,22473,22474,22475,22476,22477,22478,22479,22480,22481,22482,22483,
9450722484,22485,22486,22487,22488,22489,22490,22491,22492,22493,22494,22495,
9450822496,22497,22498,22499,22500,22501,22502,22503,22504,22505,22506,22507,
9450922508,22509,22510,22511,22512,22513,22514,22515,22516,22517,22518,22519,
9451022520,22521,22522,22523,22524,22525,22526,22527,22528,22529,22530,22531,
9451122532,22533,22534,22535,22536,22537,22538,22539,22540,22541,22542,22543,
9451222544,22545,22546,22547,22548,22549,22550,22551,22552,22553,22554,22555,
9451322556,22557,22558,22559,22560,22561,22562,22563,22564,22565,22566,22567,
9451422568,22569,22570,22571,22572,22573,22574,22575,22576,22577,22578,22579,
9451522580,22581,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,
9451622592,22593,22594,22595,22596,22597,22598,22599,22600,22601,22602,22603,
9451722604,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,22615,
9451822616,22617,22618,22619,22620,22621,22622,22623,22624,22625,22626,22627,
9451922628,22629,22630,22631,22632,22633,22634,22635,22636,22637,22638,22639,
9452022640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,
9452122652,22653,22654,22655,22656,22657,22658,22659,22660,22661,22662,22663,
9452222664,22665,22666,22667,22668,22669,22670,22671,22672,22673,22674,22675,
9452322676,22677,22678,22679,22680,22681,22682,22683,22684,22685,22686,22687,
9452422688,22689,22690,22691,22692,22693,22694,22695,22696,22697,22698,22699,
9452522700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,
9452622712,22713,22714,22715,22716,22717,22718,22719,22720,22721,22722,22723,
9452722724,22725,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,
9452822736,22737,22738,22739,22740,22741,22742,22743,22744,22745,22746,22747,
9452922748,22749,22750,22751,22752,22753,22754,22755,22756,22757,22758,22759,
9453022760,22761,22762,22763,22764,22765,22766,22767,22768,22769,22770,22771,
9453122772,22773,22774,22775,22776,22777,22778,22779,22780,22781,22782,22783,
9453222784,22785,22786,22787,22788,22789,22790,22791,22792,22793,22794,22795,
9453322796,22797,22798,22799,22800,22801,22802,22803,22804,22805,22806,22807,
9453422808,22809,22810,22811,22812,22813,22814,22815,22816,22817,22818,22819,
9453522820,22821,22822,22823,22824,22825,22826,22827,22828,22829,22830,22831,
9453622832,22833,22834,22835,22836,22837,22838,22839,22840,22841,22842,22843,
9453722844,22845,22846,22847,22848,22849,22850,22851,22852,22853,22854,22855,
9453822856,22857,22858,22859,22860,22861,22862,22863,22864,22865,22866,22867,
9453922868,22869,22870,22871,22872,22873,22874,22875,22876,22877,22878,22879,
9454022880,22881,22882,22883,22884,22885,22886,22887,22888,22889,22890,22891,
9454122892,22893,22894,22895,22896,22897,22898,22899,22900,22901,22902,22903,
9454222904,22905,22906,22907,22908,22909,22910,22911,22912,22913,22914,22915,
9454322916,22917,22918,22919,22920,22921,22922,22923,22924,22925,22926,22927,
9454422928,22929,22930,22931,22932,22933,22934,22935,22936,22937,22938,22939,
9454522940,22941,22942,22943,22944,22945,22946,22947,22948,22949,22950,22951,
9454622952,22953,22954,22955,22956,22957,22958,22959,22960,22961,22962,22963,
9454722964,22965,22966,22967,22968,22969,22970,22971,22972,22973,22974,22975,
9454822976,22977,22978,22979,22980,22981,22982,22983,22984,22985,22986,22987,
9454922988,22989,22990,22991,22992,22993,22994,22995,22996,22997,22998,22999,
9455023000,23001,23002,23003,23004,23005,23006,23007,23008,23009,23010,23011,
9455123012,23013,23014,23015,23016,23017,23018,23019,23020,23021,23022,23023,
9455223024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034,23035,
9455323036,23037,23038,23039,23040,23041,23042,23043,23044,23045,23046,23047,
9455423048,23049,23050,23051,23052,23053,23054,23055,23056,23057,23058,23059,
9455523060,23061,23062,23063,23064,23065,23066,23067,23068,23069,23070,23071,
9455623072,23073,23074,23075,23076,23077,23078,23079,23080,23081,23082,23083,
9455723084,23085,23086,23087,23088,23089,23090,23091,23092,23093,23094,23095,
9455823096,23097,23098,23099,23100,23101,23102,23103,23104,23105,23106,23107,
9455923108,23109,23110,23111,23112,23113,23114,23115,23116,23117,23118,23119,
9456023120,23121,23122,23123,23124,23125,23126,23127,23128,23129,23130,23131,
9456123132,23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,23143,
9456223144,23145,23146,23147,23148,23149,23150,23151,23152,23153,23154,23155,
9456323156,23157,23158,23159,23160,23161,23162,23163,23164,23165,23166,23167,
9456423168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,
9456523180,23181,23182,23183,23184,23185,23186,23187,23188,23189,23190,23191,
9456623192,23193,23194,23195,23196,23197,23198,23199,23200,23201,23202,23203,
9456723204,23205,23206,23207,23208,23209,23210,23211,23212,23213,23214,23215,
9456823216,23217,23218,23219,23220,23221,23222,23223,23224,23225,23226,23227,
9456923228,23229,23230,23231,23232,23233,23234,23235,23236,23237,23238,23239,
9457023240,23241,23242,23243,23244,23245,23246,23247,23248,23249,23250,23251,
9457123252,23253,23254,23255,23256,23257,23258,23259,23260,23261,23262,23263,
9457223264,23265,23266,23267,23268,23269,23270,23271,23272,23273,23274,23275,
9457323276,23277,23278,23279,23280,23281,23282,23283,23284,23285,23286,23287,
9457423288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,
9457523300,23301,23302,23303,23304,23305,23306,23307,23308,23309,23310,23311,
9457623312,23313,23314,23315,23316,23317,23318,23319,23320,23321,23322,23323,
9457723324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,
9457823336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23346,23347,
9457923348,23349,23350,23351,23352,23353,23354,23355,23356,23357,23358,23359,
9458023360,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,
9458123372,23373,23374,23375,23376,23377,23378,23379,23380,23381,23382,23383,
9458223384,23385,23386,23387,23388,23389,23390,23391,23392,23393,23394,23395,
9458323396,23397,23398,23399,23400,23401,23402,23403,23404,23405,23406,23407,
9458423408,23409,23410,23411,23412,23413,23414,23415,23416,23417,23418,23419,
9458523420,23421,23422,23423,23424,23425,23426,23427,23428,23429,23430,23431,
9458623432,23433,23434,23435,23436,23437,23438,23439,23440,23441,23442,23443,
9458723444,23445,23446,23447,23448,23449,23450,23451,23452,23453,23454,23455,
9458823456,23457,23458,23459,23460,23461,23462,23463,23464,23465,23466,23467,
9458923468,23469,23470,23471,23472,23473,23474,23475,23476,23477,23478,23479,
9459023480,23481,23482,23483,23484,23485,23486,23487,23488,23489,23490,23491,
9459123492,23493,23494,23495,23496,23497,23498,23499,23500,23501,23502,23503,
9459223504,23505,23506,23507,23508,23509,23510,23511,23512,23513,23514,23515,
9459323516,23517,23518,23519,23520,23521,23522,23523,23524,23525,23526,23527,
9459423528,23529,23530,23531,23532,23533,23534,23535,23536,23537,23538,23539,
9459523540,23541,23542,23543,23544,23545,23546,23547,23548,23549,23550,23551,
9459623552,23553,23554,23555,23556,23557,23558,23559,23560,23561,23562,23563,
9459723564,23565,23566,23567,23568,23569,23570,23571,23572,23573,23574,23575,
9459823576,23577,23578,23579,23580,23581,23582,23583,23584,23585,23586,23587,
9459923588,23589,23590,23591,23592,23593,23594,23595,23596,23597,23598,23599,
9460023600,23601,23602,23603,23604,23605,23606,23607,23608,23609,23610,23611,
9460123612,23613,23614,23615,23616,23617,23618,23619,23620,23621,23622,23623,
9460223624,23625,23626,23627,23628,23629,23630,23631,23632,23633,23634,23635,
9460323636,23637,23638,23639,23640,23641,23642,23643,23644,23645,23646,23647,
9460423648,23649,23650,23651,23652,23653,23654,23655,23656,23657,23658,23659,
9460523660,23661,23662,23663,23664,23665,23666,23667,23668,23669,23670,23671,
9460623672,23673,23674,23675,23676,23677,23678,23679,23680,23681,23682,23683,
9460723684,23685,23686,23687,23688,23689,23690,23691,23692,23693,23694,23695,
9460823696,23697,23698,23699,23700,23701,23702,23703,23704,23705,23706,23707,
9460923708,23709,23710,23711,23712,23713,23714,23715,23716,23717,23718,23719,
9461023720,23721,23722,23723,23724,23725,23726,23727,23728,23729,23730,23731,
9461123732,23733,23734,23735,23736,23737,23738,23739,23740,23741,23742,23743,
9461223744,23745,23746,23747,23748,23749,23750,23751,23752,23753,23754,23755,
9461323756,23757,23758,23759,23760,23761,23762,23763,23764,23765,23766,23767,
9461423768,23769,23770,23771,23772,23773,23774,23775,23776,23777,23778,23779,
9461523780,23781,23782,23783,23784,23785,23786,23787,23788,23789,23790,23791,
9461623792,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23803,
9461723804,23805,23806,23807,23808,23809,23810,23811,23812,23813,23814,23815,
9461823816,23817,23818,23819,23820,23821,23822,23823,23824,23825,23826,23827,
9461923828,23829,23830,23831,23832,23833,23834,23835,23836,23837,23838,23839,
9462023840,23841,23842,23843,23844,23845,23846,23847,23848,23849,23850,23851,
9462123852,23853,23854,23855,23856,23857,23858,23859,23860,23861,23862,23863,
9462223864,23865,23866,23867,23868,23869,23870,23871,23872,23873,23874,23875,
9462323876,23877,23878,23879,23880,23881,23882,23883,23884,23885,23886,23887,
9462423888,23889,23890,23891,23892,23893,23894,23895,23896,23897,23898,23899,
9462523900,23901,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,
9462623912,23913,23914,23915,23916,23917,23918,23919,23920,23921,23922,23923,
9462723924,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,
9462823936,23937,23938,23939,23940,23941,23942,23943,23944,23945,23946,23947,
9462923948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,
9463023960,23961,23962,23963,23964,23965,23966,23967,23968,23969,23970,23971,
9463123972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,
9463223984,23985,23986,23987,23988,23989,23990,23991,23992,23993,23994,23995,
9463323996,23997,23998,23999,24000,24001,24002,24003,24004,24005,24006,24007,
9463424008,24009,24010,24011,24012,24013,24014,24015,24016,24017,24018,24019,
9463524020,24021,24022,24023,24024,24025,24026,24027,24028,24029,24030,24031,
9463624032,24033,24034,24035,24036,24037,24038,24039,24040,24041,24042,24043,
9463724044,24045,24046,24047,24048,24049,24050,24051,24052,24053,24054,24055,
9463824056,24057,24058,24059,24060,24061,24062,24063,24064,24065,24066,24067,
9463924068,24069,24070,24071,24072,24073,24074,24075,24076,24077,24078,24079,
9464024080,24081,24082,24083,24084,24085,24086,24087,24088,24089,24090,24091,
9464124092,24093,24094,24095,24096,24097,24098,24099,24100,24101,24102,24103,
9464224104,24105,24106,24107,24108,24109,24110,24111,24112,24113,24114,24115,
9464324116,24117,24118,24119,24120,24121,24122,24123,24124,24125,24126,24127,
9464424128,24129,24130,24131,24132,24133,24134,24135,24136,24137,24138,24139,
9464524140,24141,24142,24143,24144,24145,24146,24147,24148,24149,24150,24151,
9464624152,24153,24154,24155,24156,24157,24158,24159,24160,24161,24162,24163,
9464724164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,
9464824176,24177,24178,24179,24180,24181,24182,24183,24184,24185,24186,24187,
9464924188,24189,24190,24191,24192,24193,24194,24195,24196,24197,24198,24199,
9465024200,24201,24202,24203,24204,24205,24206,24207,24208,24209,24210,24211,
9465124212,24213,24214,24215,24216,24217,24218,24219,24220,24221,24222,24223,
9465224224,24225,24226,24227,24228,24229,24230,24231,24232,24233,24234,24235,
9465324236,24237,24238,24239,24240,24241,24242,24243,24244,24245,24246,24247,
9465424248,24249,24250,24251,24252,24253,24254,24255,24256,24257,24258,24259,
9465524260,24261,24262,24263,24264,24265,24266,24267,24268,24269,24270,24271,
9465624272,24273,24274,24275,24276,24277,24278,24279,24280,24281,24282,24283,
9465724284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,
9465824296,24297,24298,24299,24300,24301,24302,24303,24304,24305,24306,24307,
9465924308,24309,24310,24311,24312,24313,24314,24315,24316,24317,24318,24319,
9466024320,24321,24322,24323,24324,24325,24326,24327,24328,24329,24330,24331,
9466124332,24333,24334,24335,24336,24337,24338,24339,24340,24341,24342,24343,
9466224344,24345,24346,24347,24348,24349,24350,24351,24352,24353,24354,24355,
9466324356,24357,24358,24359,24360,24361,24362,24363,24364,24365,24366,24367,
9466424368,24369,24370,24371,24372,24373,24374,24375,24376,24377,24378,24379,
9466524380,24381,24382,24383,24384,24385,24386,24387,24388,24389,24390,24391,
9466624392,24393,24394,24395,24396,24397,24398,24399,24400,24401,24402,24403,
9466724404,24405,24406,24407,24408,24409,24410,24411,24412,24413,24414,24415,
9466824416,24417,24418,24419,24420,24421,24422,24423,24424,24425,24426,24427,
9466924428,24429,24430,24431,24432,24433,24434,24435,24436,24437,24438,24439,
9467024440,24441,24442,24443,24444,24445,24446,24447,24448,24449,24450,24451,
9467124452,24453,24454,24455,24456,24457,24458,24459,24460,24461,24462,24463,
9467224464,24465,24466,24467,24468,24469,24470,24471,24472,24473,24474,24475,
9467324476,24477,24478,24479,24480,24481,24482,24483,24484,24485,24486,24487,
9467424488,24489,24490,24491,24492,24493,24494,24495,24496,24497,24498,24499,
9467524500,24501,24502,24503,24504,24505,24506,24507,24508,24509,24510,24511,
9467624512,24513,24514,24515,24516,24517,24518,24519,24520,24521,24522,24523,
9467724524,24525,24526,24527,24528,24529,24530,24531,24532,24533,24534,24535,
9467824536,24537,24538,24539,24540,24541,24542,24543,24544,24545,24546,24547,
9467924548,24549,24550,24551,24552,24553,24554,24555,24556,24557,24558,24559,
9468024560,24561,24562,24563,24564,24565,24566,24567,24568,24569,24570,24571,
9468124572,24573,24574,24575,24576,24577,24578,24579,24580,24581,24582,24583,
9468224584,24585,24586,24587,24588,24589,24590,24591,24592,24593,24594,24595,
9468324596,24597,24598,24599,24600,24601,24602,24603,24604,24605,24606,24607,
9468424608,24609,24610,24611,24612,24613,24614,24615,24616,24617,24618,24619,
9468524620,24621,24622,24623,24624,24625,24626,24627,24628,24629,24630,24631,
9468624632,24633,24634,24635,24636,24637,24638,24639,24640,24641,24642,24643,
9468724644,24645,24646,24647,24648,24649,24650,24651,24652,24653,24654,24655,
9468824656,24657,24658,24659,24660,24661,24662,24663,24664,24665,24666,24667,
9468924668,24669,24670,24671,24672,24673,24674,24675,24676,24677,24678,24679,
9469024680,24681,24682,24683,24684,24685,24686,24687,24688,24689,24690,24691,
9469124692,24693,24694,24695,24696,24697,24698,24699,24700,24701,24702,24703,
9469224704,24705,24706,24707,24708,24709,24710,24711,24712,24713,24714,24715,
9469324716,24717,24718,24719,24720,24721,24722,24723,24724,24725,24726,24727,
9469424728,24729,24730,24731,24732,24733,24734,24735,24736,24737,24738,24739,
9469524740,24741,24742,24743,24744,24745,24746,24747,24748,24749,24750,24751,
9469624752,24753,24754,24755,24756,24757,24758,24759,24760,24761,24762,24763,
9469724764,24765,24766,24767,24768,24769,24770,24771,24772,24773,24774,24775,
9469824776,24777,24778,24779,24780,24781,24782,24783,24784,24785,24786,24787,
9469924788,24789,24790,24791,24792,24793,24794,24795,24796,24797,24798,24799,
9470024800,24801,24802,24803,24804,24805,24806,24807,24808,24809,24810,24811,
9470124812,24813,24814,24815,24816,24817,24818,24819,24820,24821,24822,24823,
9470224824,24825,24826,24827,24828,24829,24830,24831,24832,24833,24834,24835,
9470324836,24837,24838,24839,24840,24841,24842,24843,24844,24845,24846,24847,
9470424848,24849,24850,24851,24852,24853,24854,24855,24856,24857,24858,24859,
9470524860,24861,24862,24863,24864,24865,24866,24867,24868,24869,24870,24871,
9470624872,24873,24874,24875,24876,24877,24878,24879,24880,24881,24882,24883,
9470724884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24895,
9470824896,24897,24898,24899,24900,24901,24902,24903,24904,24905,24906,24907,
9470924908,24909,24910,24911,24912,24913,24914,24915,24916,24917,24918,24919,
9471024920,24921,24922,24923,24924,24925,24926,24927,24928,24929,24930,24931,
9471124932,24933,24934,24935,24936,24937,24938,24939,24940,24941,24942,24943,
9471224944,24945,24946,24947,24948,24949,24950,24951,24952,24953,24954,24955,
9471324956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,
9471424968,24969,24970,24971,24972,24973,24974,24975,24976,24977,24978,24979,
9471524980,24981,24982,24983,24984,24985,24986,24987,24988,24989,24990,24991,
9471624992,24993,24994,24995,24996,24997,24998,24999,25000,25001,25002,25003,
9471725004,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25015,
9471825016,25017,25018,25019,25020,25021,25022,25023,25024,25025,25026,25027,
9471925028,25029,25030,25031,25032,25033,25034,25035,25036,25037,25038,25039,
9472025040,25041,25042,25043,25044,25045,25046,25047,25048,25049,25050,25051,
9472125052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25062,25063,
9472225064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,
9472325076,25077,25078,25079,25080,25081,25082,25083,25084,25085,25086,25087,
9472425088,25089,25090,25091,25092,25093,25094,25095,25096,25097,25098,25099,
9472525100,25101,25102,25103,25104,25105,25106,25107,25108,25109,25110,25111,
9472625112,25113,25114,25115,25116,25117,25118,25119,25120,25121,25122,25123,
9472725124,25125,25126,25127,25128,25129,25130,25131,25132,25133,25134,25135,
9472825136,25137,25138,25139,25140,25141,25142,25143,25144,25145,25146,25147,
9472925148,25149,25150,25151,25152,25153,25154,25155,25156,25157,25158,25159,
9473025160,25161,25162,25163,25164,25165,25166,25167,25168,25169,25170,25171,
9473125172,25173,25174,25175,25176,25177,25178,25179,25180,25181,25182,25183,
9473225184,25185,25186,25187,25188,25189,25190,25191,25192,25193,25194,25195,
9473325196,25197,25198,25199,25200,25201,25202,25203,25204,25205,25206,25207,
9473425208,25209,25210,25211,25212,25213,25214,25215,25216,25217,25218,25219,
9473525220,25221,25222,25223,25224,25225,25226,25227,25228,25229,25230,25231,
9473625232,25233,25234,25235,25236,25237,25238,25239,25240,25241,25242,25243,
9473725244,25245,25246,25247,25248,25249,25250,25251,25252,25253,25254,25255,
9473825256,25257,25258,25259,25260,25261,25262,25263,25264,25265,25266,25267,
9473925268,25269,25270,25271,25272,25273,25274,25275,25276,25277,25278,25279,
9474025280,25281,25282,25283,25284,25285,25286,25287,25288,25289,25290,25291,
9474125292,25293,25294,25295,25296,25297,25298,25299,25300,25301,25302,25303,
9474225304,25305,25306,25307,25308,25309,25310,25311,25312,25313,25314,25315,
9474325316,25317,25318,25319,25320,25321,25322,25323,25324,25325,25326,25327,
9474425328,25329,25330,25331,25332,25333,25334,25335,25336,25337,25338,25339,
9474525340,25341,25342,25343,25344,25345,25346,25347,25348,25349,25350,25351,
9474625352,25353,25354,25355,25356,25357,25358,25359,25360,25361,25362,25363,
9474725364,25365,25366,25367,25368,25369,25370,25371,25372,25373,25374,25375,
9474825376,25377,25378,25379,25380,25381,25382,25383,25384,25385,25386,25387,
9474925388,25389,25390,25391,25392,25393,25394,25395,25396,25397,25398,25399,
9475025400,25401,25402,25403,25404,25405,25406,25407,25408,25409,25410,25411,
9475125412,25413,25414,25415,25416,25417,25418,25419,25420,25421,25422,25423,
9475225424,25425,25426,25427,25428,25429,25430,25431,25432,25433,25434,25435,
9475325436,25437,25438,25439,25440,25441,25442,25443,25444,25445,25446,25447,
9475425448,25449,25450,25451,25452,25453,25454,25455,25456,25457,25458,25459,
9475525460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471,
9475625472,25473,25474,25475,25476,25477,25478,25479,25480,25481,25482,25483,
9475725484,25485,25486,25487,25488,25489,25490,25491,25492,25493,25494,25495,
9475825496,25497,25498,25499,25500,25501,25502,25503,25504,25505,25506,25507,
9475925508,25509,25510,25511,25512,25513,25514,25515,25516,25517,25518,25519,
9476025520,25521,25522,25523,25524,25525,25526,25527,25528,25529,25530,25531,
9476125532,25533,25534,25535,25536,25537,25538,25539,25540,25541,25542,25543,
9476225544,25545,25546,25547,25548,25549,25550,25551,25552,25553,25554,25555,
9476325556,25557,25558,25559,25560,25561,25562,25563,25564,25565,25566,25567,
9476425568,25569,25570,25571,25572,25573,25574,25575,25576,25577,25578,25579,
9476525580,25581,25582,25583,25584,25585,25586,25587,25588,25589,25590,25591,
9476625592,25593,25594,25595,25596,25597,25598,25599,25600,25601,25602,25603,
9476725604,25605,25606,25607,25608,25609,25610,25611,25612,25613,25614,25615,
9476825616,25617,25618,25619,25620,25621,25622,25623,25624,25625,25626,25627,
9476925628,25629,25630,25631,25632,25633,25634,25635,25636,25637,25638,25639,
9477025640,25641,25642,25643,25644,25645,25646,25647,25648,25649,25650,25651,
9477125652,25653,25654,25655,25656,25657,25658,25659,25660,25661,25662,25663,
9477225664,25665,25666,25667,25668,25669,25670,25671,25672,25673,25674,25675,
9477325676,25677,25678,25679,25680,25681,25682,25683,25684,25685,25686,25687,
9477425688,25689,25690,25691,25692,25693,25694,25695,25696,25697,25698,25699,
9477525700,25701,25702,25703,25704,25705,25706,25707,25708,25709,25710,25711,
9477625712,25713,25714,25715,25716,25717,25718,25719,25720,25721,25722,25723,
9477725724,25725,25726,25727,25728,25729,25730,25731,25732,25733,25734,25735,
9477825736,25737,25738,25739,25740,25741,25742,25743,25744,25745,25746,25747,
9477925748,25749,25750,25751,25752,25753,25754,25755,25756,25757,25758,25759,
9478025760,25761,25762,25763,25764,25765,25766,25767,25768,25769,25770,25771,
9478125772,25773,25774,25775,25776,25777,25778,25779,25780,25781,25782,25783,
9478225784,25785,25786,25787,25788,25789,25790,25791,25792,25793,25794,25795,
9478325796,25797,25798,25799,25800,25801,25802,25803,25804,25805,25806,25807,
9478425808,25809,25810,25811,25812,25813,25814,25815,25816,25817,25818,25819,
9478525820,25821,25822,25823,25824,25825,25826,25827,25828,25829,25830,25831,
9478625832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,
9478725844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,
9478825856,25857,25858,25859,25860,25861,25862,25863,25864,25865,25866,25867,
9478925868,25869,25870,25871,25872,25873,25874,25875,25876,25877,25878,25879,
9479025880,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,
9479125892,25893,25894,25895,25896,25897,25898,25899,25900,25901,25902,25903,
9479225904,25905,25906,25907,25908,25909,25910,25911,25912,25913,25914,25915,
9479325916,25917,25918,25919,25920,25921,25922,25923,25924,25925,25926,25927,
9479425928,25929,25930,25931,25932,25933,25934,25935,25936,25937,25938,25939,
9479525940,25941,25942,25943,25944,25945,25946,25947,25948,25949,25950,25951,
9479625952,25953,25954,25955,25956,25957,25958,25959,25960,25961,25962,25963,
9479725964,25965,25966,25967,25968,25969,25970,25971,25972,25973,25974,25975,
9479825976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,
9479925988,25989,25990,25991,25992,25993,25994,25995,25996,25997,25998,25999,
9480026000,26001,26002,26003,26004,26005,26006,26007,26008,26009,26010,26011,
9480126012,26013,26014,26015,26016,26017,26018,26019,26020,26021,26022,26023,
9480226024,26025,26026,26027,26028,26029,26030,26031,26032,26033,26034,26035,
9480326036,26037,26038,26039,26040,26041,26042,26043,26044,26045,26046,26047,
9480426048,26049,26050,26051,26052,26053,26054,26055,26056,26057,26058,26059,
9480526060,26061,26062,26063,26064,26065,26066,26067,26068,26069,26070,26071,
9480626072,26073,26074,26075,26076,26077,26078,26079,26080,26081,26082,26083,
9480726084,26085,26086,26087,26088,26089,26090,26091,26092,26093,26094,26095,
9480826096,26097,26098,26099,26100,26101,26102,26103,26104,26105,26106,26107,
9480926108,26109,26110,26111,26112,26113,26114,26115,26116,26117,26118,26119,
9481026120,26121,26122,26123,26124,26125,26126,26127,26128,26129,26130,26131,
9481126132,26133,26134,26135,26136,26137,26138,26139,26140,26141,26142,26143,
9481226144,26145,26146,26147,26148,26149,26150,26151,26152,26153,26154,26155,
9481326156,26157,26158,26159,26160,26161,26162,26163,26164,26165,26166,26167,
9481426168,26169,26170,26171,26172,26173,26174,26175,26176,26177,26178,26179,
9481526180,26181,26182,26183,26184,26185,26186,26187,26188,26189,26190,26191,
9481626192,26193,26194,26195,26196,26197,26198,26199,26200,26201,26202,26203,
9481726204,26205,26206,26207,26208,26209,26210,26211,26212,26213,26214,26215,
9481826216,26217,26218,26219,26220,26221,26222,26223,26224,26225,26226,26227,
9481926228,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239,
9482026240,26241,26242,26243,26244,26245,26246,26247,26248,26249,26250,26251,
9482126252,26253,26254,26255,26256,26257,26258,26259,26260,26261,26262,26263,
9482226264,26265,26266,26267,26268,26269,26270,26271,26272,26273,26274,26275,
9482326276,26277,26278,26279,26280,26281,26282,26283,26284,26285,26286,26287,
9482426288,26289,26290,26291,26292,26293,26294,26295,26296,26297,26298,26299,
9482526300,26301,26302,26303,26304,26305,26306,26307,26308,26309,26310,26311,
9482626312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,
9482726324,26325,26326,26327,26328,26329,26330,26331,26332,26333,26334,26335,
9482826336,26337,26338,26339,26340,26341,26342,26343,26344,26345,26346,26347,
9482926348,26349,26350,26351,26352,26353,26354,26355,26356,26357,26358,26359,
9483026360,26361,26362,26363,26364,26365,26366,26367,26368,26369,26370,26371,
9483126372,26373,26374,26375,26376,26377,26378,26379,26380,26381,26382,26383,
9483226384,26385,26386,26387,26388,26389,26390,26391,26392,26393,26394,26395,
9483326396,26397,26398,26399,26400,26401,26402,26403,26404,26405,26406,26407,
9483426408,26409,26410,26411,26412,26413,26414,26415,26416,26417,26418,26419,
9483526420,26421,26422,26423,26424,26425,26426,26427,26428,26429,26430,26431,
9483626432,26433,26434,26435,26436,26437,26438,26439,26440,26441,26442,26443,
9483726444,26445,26446,26447,26448,26449,26450,26451,26452,26453,26454,26455,
9483826456,26457,26458,26459,26460,26461,26462,26463,26464,26465,26466,26467,
9483926468,26469,26470,26471,26472,26473,26474,26475,26476,26477,26478,26479,
9484026480,26481,26482,26483,26484,26485,26486,26487,26488,26489,26490,26491,
9484126492,26493,26494,26495,26496,26497,26498,26499,26500,26501,26502,26503,
9484226504,26505,26506,26507,26508,26509,26510,26511,26512,26513,26514,26515,
9484326516,26517,26518,26519,26520,26521,26522,26523,26524,26525,26526,26527,
9484426528,26529,26530,26531,26532,26533,26534,26535,26536,26537,26538,26539,
9484526540,26541,26542,26543,26544,26545,26546,26547,26548,26549,26550,26551,
9484626552,26553,26554,26555,26556,26557,26558,26559,26560,26561,26562,26563,
9484726564,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26575,
9484826576,26577,26578,26579,26580,26581,26582,26583,26584,26585,26586,26587,
9484926588,26589,26590,26591,26592,26593,26594,26595,26596,26597,26598,26599,
9485026600,26601,26602,26603,26604,26605,26606,26607,26608,26609,26610,26611,
9485126612,26613,26614,26615,26616,26617,26618,26619,26620,26621,26622,26623,
9485226624,26625,26626,26627,26628,26629,26630,26631,26632,26633,26634,26635,
9485326636,26637,26638,26639,26640,26641,26642,26643,26644,26645,26646,26647,
9485426648,26649,26650,26651,26652,26653,26654,26655,26656,26657,26658,26659,
9485526660,26661,26662,26663,26664,26665,26666,26667,26668,26669,26670,26671,
9485626672,26673,26674,26675,26676,26677,26678,26679,26680,26681,26682,26683,
9485726684,26685,26686,26687,26688,26689,26690,26691,26692,26693,26694,26695,
9485826696,26697,26698,26699,26700,26701,26702,26703,26704,26705,26706,26707,
9485926708,26709,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,
9486026720,26721,26722,26723,26724,26725,26726,26727,26728,26729,26730,26731,
9486126732,26733,26734,26735,26736,26737,26738,26739,26740,26741,26742,26743,
9486226744,26745,26746,26747,26748,26749,26750,26751,26752,26753,26754,26755,
9486326756,26757,26758,26759,26760,26761,26762,26763,26764,26765,26766,26767,
9486426768,26769,26770,26771,26772,26773,26774,26775,26776,26777,26778,26779,
9486526780,26781,26782,26783,26784,26785,26786,26787,26788,26789,26790,26791,
9486626792,26793,26794,26795,26796,26797,26798,26799,26800,26801,26802,26803,
9486726804,26805,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,
9486826816,26817,26818,26819,26820,26821,26822,26823,26824,26825,26826,26827,
9486926828,26829,26830,26831,26832,26833,26834,26835,26836,26837,26838,26839,
9487026840,26841,26842,26843,26844,26845,26846,26847,26848,26849,26850,26851,
9487126852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26862,26863,
9487226864,26865,26866,26867,26868,26869,26870,26871,26872,26873,26874,26875,
9487326876,26877,26878,26879,26880,26881,26882,26883,26884,26885,26886,26887,
9487426888,26889,26890,26891,26892,26893,26894,26895,26896,26897,26898,26899,
9487526900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26911,
9487626912,26913,26914,26915,26916,26917,26918,26919,26920,26921,26922,26923,
9487726924,26925,26926,26927,26928,26929,26930,26931,26932,26933,26934,26935,
9487826936,26937,26938,26939,26940,26941,26942,26943,26944,26945,26946,26947,
9487926948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,
9488026960,26961,26962,26963,26964,26965,26966,26967,26968,26969,26970,26971,
9488126972,26973,26974,26975,26976,26977,26978,26979,26980,26981,26982,26983,
9488226984,26985,26986,26987,26988,26989,26990,26991,26992,26993,26994,26995,
9488326996,26997,26998,26999,27000,27001,27002,27003,27004,27005,27006,27007,
9488427008,27009,27010,27011,27012,27013,27014,27015,27016,27017,27018,27019,
9488527020,27021,27022,27023,27024,27025,27026,27027,27028,27029,27030,27031,
9488627032,27033,27034,27035,27036,27037,27038,27039,27040,27041,27042,27043,
9488727044,27045,27046,27047,27048,27049,27050,27051,27052,27053,27054,27055,
9488827056,27057,27058,27059,27060,27061,27062,27063,27064,27065,27066,27067,
9488927068,27069,27070,27071,27072,27073,27074,27075,27076,27077,27078,27079,
9489027080,27081,27082,27083,27084,27085,27086,27087,27088,27089,27090,27091,
9489127092,27093,27094,27095,27096,27097,27098,27099,27100,27101,27102,27103,
9489227104,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,
9489327116,27117,27118,27119,27120,27121,27122,27123,27124,27125,27126,27127,
9489427128,27129,27130,27131,27132,27133,27134,27135,27136,27137,27138,27139,
9489527140,27141,27142,27143,27144,27145,27146,27147,27148,27149,27150,27151,
9489627152,27153,27154,27155,27156,27157,27158,27159,27160,27161,27162,27163,
9489727164,27165,27166,27167,27168,27169,27170,27171,27172,27173,27174,27175,
9489827176,27177,27178,27179,27180,27181,27182,27183,27184,27185,27186,27187,
9489927188,27189,27190,27191,27192,27193,27194,27195,27196,27197,27198,27199,
9490027200,27201,27202,27203,27204,27205,27206,27207,27208,27209,27210,27211,
9490127212,27213,27214,27215,27216,27217,27218,27219,27220,27221,27222,27223,
9490227224,27225,27226,27227,27228,27229,27230,27231,27232,27233,27234,27235,
9490327236,27237,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,
9490427248,27249,27250,27251,27252,27253,27254,27255,27256,27257,27258,27259,
9490527260,27261,27262,27263,27264,27265,27266,27267,27268,27269,27270,27271,
9490627272,27273,27274,27275,27276,27277,27278,27279,27280,27281,27282,27283,
9490727284,27285,27286,27287,27288,27289,27290,27291,27292,27293,27294,27295,
9490827296,27297,27298,27299,27300,27301,27302,27303,27304,27305,27306,27307,
9490927308,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,
9491027320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,
9491127332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,
9491227344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,
9491327356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,
9491427368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,
9491527380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,
9491627392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,
9491727404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,
9491827416,27417,27418,27419,27420,27421,27422,27423,27424,27425,27426,27427,
9491927428,27429,27430,27431,27432,27433,27434,27435,27436,27437,27438,27439,
9492027440,27441,27442,27443,27444,27445,27446,27447,27448,27449,27450,27451,
9492127452,27453,27454,27455,27456,27457,27458,27459,27460,27461,27462,27463,
9492227464,27465,27466,27467,27468,27469,27470,27471,27472,27473,27474,27475,
9492327476,27477,27478,27479,27480,27481,27482,27483,27484,27485,27486,27487,
9492427488,27489,27490,27491,27492,27493,27494,27495,27496,27497,27498,27499,
9492527500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,
9492627512,27513,27514,27515,27516,27517,27518,27519,27520,27521,27522,27523,
9492727524,27525,27526,27527,27528,27529,27530,27531,27532,27533,27534,27535,
9492827536,27537,27538,27539,27540,27541,27542,27543,27544,27545,27546,27547,
9492927548,27549,27550,27551,27552,27553,27554,27555,27556,27557,27558,27559,
9493027560,27561,27562,27563,27564,27565,27566,27567,27568,27569,27570,27571,
9493127572,27573,27574,27575,27576,27577,27578,27579,27580,27581,27582,27583,
9493227584,27585,27586,27587,27588,27589,27590,27591,27592,27593,27594,27595,
9493327596,27597,27598,27599,27600,27601,27602,27603,27604,27605,27606,27607,
9493427608,27609,27610,27611,27612,27613,27614,27615,27616,27617,27618,27619,
9493527620,27621,27622,27623,27624,27625,27626,27627,27628,27629,27630,27631,
9493627632,27633,27634,27635,27636,27637,27638,27639,27640,27641,27642,27643,
9493727644,27645,27646,27647,27648,27649,27650,27651,27652,27653,27654,27655,
9493827656,27657,27658,27659,27660,27661,27662,27663,27664,27665,27666,27667,
9493927668,27669,27670,27671,27672,27673,27674,27675,27676,27677,27678,27679,
9494027680,27681,27682,27683,27684,27685,27686,27687,27688,27689,27690,27691,
9494127692,27693,27694,27695,27696,27697,27698,27699,27700,27701,27702,27703,
9494227704,27705,27706,27707,27708,27709,27710,27711,27712,27713,27714,27715,
9494327716,27717,27718,27719,27720,27721,27722,27723,27724,27725,27726,27727,
9494427728,27729,27730,27731,27732,27733,27734,27735,27736,27737,27738,27739,
9494527740,27741,27742,27743,27744,27745,27746,27747,27748,27749,27750,27751,
9494627752,27753,27754,27755,27756,27757,27758,27759,27760,27761,27762,27763,
9494727764,27765,27766,27767,27768,27769,27770,27771,27772,27773,27774,27775,
9494827776,27777,27778,27779,27780,27781,27782,27783,27784,27785,27786,27787,
9494927788,27789,27790,27791,27792,27793,27794,27795,27796,27797,27798,27799,
9495027800,27801,27802,27803,27804,27805,27806,27807,27808,27809,27810,27811,
9495127812,27813,27814,27815,27816,27817,27818,27819,27820,27821,27822,27823,
9495227824,27825,27826,27827,27828,27829,27830,27831,27832,27833,27834,27835,
9495327836,27837,27838,27839,27840,27841,27842,27843,27844,27845,27846,27847,
9495427848,27849,27850,27851,27852,27853,27854,27855,27856,27857,27858,27859,
9495527860,27861,27862,27863,27864,27865,27866,27867,27868,27869,27870,27871,
9495627872,27873,27874,27875,27876,27877,27878,27879,27880,27881,27882,27883,
9495727884,27885,27886,27887,27888,27889,27890,27891,27892,27893,27894,27895,
9495827896,27897,27898,27899,27900,27901,27902,27903,27904,27905,27906,27907,
9495927908,27909,27910,27911,27912,27913,27914,27915,27916,27917,27918,27919,
9496027920,27921,27922,27923,27924,27925,27926,27927,27928,27929,27930,27931,
9496127932,27933,27934,27935,27936,27937,27938,27939,27940,27941,27942,27943,
9496227944,27945,27946,27947,27948,27949,27950,27951,27952,27953,27954,27955,
9496327956,27957,27958,27959,27960,27961,27962,27963,27964,27965,27966,27967,
9496427968,27969,27970,27971,27972,27973,27974,27975,27976,27977,27978,27979,
9496527980,27981,27982,27983,27984,27985,27986,27987,27988,27989,27990,27991,
9496627992,27993,27994,27995,27996,27997,27998,27999,28000,28001,28002,28003,
9496728004,28005,28006,28007,28008,28009,28010,28011,28012,28013,28014,28015,
9496828016,28017,28018,28019,28020,28021,28022,28023,28024,28025,28026,28027,
9496928028,28029,28030,28031,28032,28033,28034,28035,28036,28037,28038,28039,
9497028040,28041,28042,28043,28044,28045,28046,28047,28048,28049,28050,28051,
9497128052,28053,28054,28055,28056,28057,28058,28059,28060,28061,28062,28063,
9497228064,28065,28066,28067,28068,28069,28070,28071,28072,28073,28074,28075,
9497328076,28077,28078,28079,28080,28081,28082,28083,28084,28085,28086,28087,
9497428088,28089,28090,28091,28092,28093,28094,28095,28096,28097,28098,28099,
9497528100,28101,28102,28103,28104,28105,28106,28107,28108,28109,28110,28111,
9497628112,28113,28114,28115,28116,28117,28118,28119,28120,28121,28122,28123,
9497728124,28125,28126,28127,28128,28129,28130,28131,28132,28133,28134,28135,
9497828136,28137,28138,28139,28140,28141,28142,28143,28144,28145,28146,28147,
9497928148,28149,28150,28151,28152,28153,28154,28155,28156,28157,28158,28159,
9498028160,28161,28162,28163,28164,28165,28166,28167,28168,28169,28170,28171,
9498128172,28173,28174,28175,28176,28177,28178,28179,28180,28181,28182,28183,
9498228184,28185,28186,28187,28188,28189,28190,28191,28192,28193,28194,28195,
9498328196,28197,28198,28199,28200,28201,28202,28203,28204,28205,28206,28207,
9498428208,28209,28210,28211,28212,28213,28214,28215,28216,28217,28218,28219,
9498528220,28221,28222,28223,28224,28225,28226,28227,28228,28229,28230,28231,
9498628232,28233,28234,28235,28236,28237,28238,28239,28240,28241,28242,28243,
9498728244,28245,28246,28247,28248,28249,28250,28251,28252,28253,28254,28255,
9498828256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28267,
9498928268,28269,28270,28271,28272,28273,28274,28275,28276,28277,28278,28279,
9499028280,28281,28282,28283,28284,28285,28286,28287,28288,28289,28290,28291,
9499128292,28293,28294,28295,28296,28297,28298,28299,28300,28301,28302,28303,
9499228304,28305,28306,28307,28308,28309,28310,28311,28312,28313,28314,28315,
9499328316,28317,28318,28319,28320,28321,28322,28323,28324,28325,28326,28327,
9499428328,28329,28330,28331,28332,28333,28334,28335,28336,28337,28338,28339,
9499528340,28341,28342,28343,28344,28345,28346,28347,28348,28349,28350,28351,
9499628352,28353,28354,28355,28356,28357,28358,28359,28360,28361,28362,28363,
9499728364,28365,28366,28367,28368,28369,28370,28371,28372,28373,28374,28375,
9499828376,28377,28378,28379,28380,28381,28382,28383,28384,28385,28386,28387,
9499928388,28389,28390,28391,28392,28393,28394,28395,28396,28397,28398,28399,
9500028400,28401,28402,28403,28404,28405,28406,28407,28408,28409,28410,28411,
9500128412,28413,28414,28415,28416,28417,28418,28419,28420,28421,28422,28423,
9500228424,28425,28426,28427,28428,28429,28430,28431,28432,28433,28434,28435,
9500328436,28437,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,
9500428448,28449,28450,28451,28452,28453,28454,28455,28456,28457,28458,28459,
9500528460,28461,28462,28463,28464,28465,28466,28467,28468,28469,28470,28471,
9500628472,28473,28474,28475,28476,28477,28478,28479,28480,28481,28482,28483,
9500728484,28485,28486,28487,28488,28489,28490,28491,28492,28493,28494,28495,
9500828496,28497,28498,28499,28500,28501,28502,28503,28504,28505,28506,28507,
9500928508,28509,28510,28511,28512,28513,28514,28515,28516,28517,28518,28519,
9501028520,28521,28522,28523,28524,28525,28526,28527,28528,28529,28530,28531,
9501128532,28533,28534,28535,28536,28537,28538,28539,28540,28541,28542,28543,
9501228544,28545,28546,28547,28548,28549,28550,28551,28552,28553,28554,28555,
9501328556,28557,28558,28559,28560,28561,28562,28563,28564,28565,28566,28567,
9501428568,28569,28570,28571,28572,28573,28574,28575,28576,28577,28578,28579,
9501528580,28581,28582,28583,28584,28585,28586,28587,28588,28589,28590,28591,
9501628592,28593,28594,28595,28596,28597,28598,28599,28600,28601,28602,28603,
9501728604,28605,28606,28607,28608,28609,28610,28611,28612,28613,28614,28615,
9501828616,28617,28618,28619,28620,28621,28622,28623,28624,28625,28626,28627,
9501928628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28638,28639,
9502028640,28641,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,
9502128652,28653,28654,28655,28656,28657,28658,28659,28660,28661,28662,28663,
9502228664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,
9502328676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,
9502428688,28689,28690,28691,28692,28693,28694,28695,28696,28697,28698,28699,
9502528700,28701,28702,28703,28704,28705,28706,28707,28708,28709,28710,28711,
9502628712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,
9502728724,28725,28726,28727,28728,28729,28730,28731,28732,28733,28734,28735,
9502828736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,
9502928748,28749,28750,28751,28752,28753,28754,28755,28756,28757,28758,28759,
9503028760,28761,28762,28763,28764,28765,28766,28767,28768,28769,28770,28771,
9503128772,28773,28774,28775,28776,28777,28778,28779,28780,28781,28782,28783,
9503228784,28785,28786,28787,28788,28789,28790,28791,28792,28793,28794,28795,
9503328796,28797,28798,28799,28800,28801,28802,28803,28804,28805,28806,28807,
9503428808,28809,28810,28811,28812,28813,28814,28815,28816,28817,28818,28819,
9503528820,28821,28822,28823,28824,28825,28826,28827,28828,28829,28830,28831,
9503628832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28843,
9503728844,28845,28846,28847,28848,28849,28850,28851,28852,28853,28854,28855,
9503828856,28857,28858,28859,28860,28861,28862,28863,28864,28865,28866,28867,
9503928868,28869,28870,28871,28872,28873,28874,28875,28876,28877,28878,28879,
9504028880,28881,28882,28883,28884,28885,28886,28887,28888,28889,28890,28891,
9504128892,28893,28894,28895,28896,28897,28898,28899,28900,28901,28902,28903,
9504228904,28905,28906,28907,28908,28909,28910,28911,28912,28913,28914,28915,
9504328916,28917,28918,28919,28920,28921,28922,28923,28924,28925,28926,28927,
9504428928,28929,28930,28931,28932,28933,28934,28935,28936,28937,28938,28939,
9504528940,28941,28942,28943,28944,28945,28946,28947,28948,28949,28950,28951,
9504628952,28953,28954,28955,28956,28957,28958,28959,28960,28961,28962,28963,
9504728964,28965,28966,28967,28968,28969,28970,28971,28972,28973,28974,28975,
9504828976,28977,28978,28979,28980,28981,28982,28983,28984,28985,28986,28987,
9504928988,28989,28990,28991,28992,28993,28994,28995,28996,28997,28998,28999,
9505029000,29001,29002,29003,29004,29005,29006,29007,29008,29009,29010,29011,
9505129012,29013,29014,29015,29016,29017,29018,29019,29020,29021,29022,29023,
9505229024,29025,29026,29027,29028,29029,29030,29031,29032,29033,29034,29035,
9505329036,29037,29038,29039,29040,29041,29042,29043,29044,29045,29046,29047,
9505429048,29049,29050,29051,29052,29053,29054,29055,29056,29057,29058,29059,
9505529060,29061,29062,29063,29064,29065,29066,29067,29068,29069,29070,29071,
9505629072,29073,29074,29075,29076,29077,29078,29079,29080,29081,29082,29083,
9505729084,29085,29086,29087,29088,29089,29090,29091,29092,29093,29094,29095,
9505829096,29097,29098,29099,29100,29101,29102,29103,29104,29105,29106,29107,
9505929108,29109,29110,29111,29112,29113,29114,29115,29116,29117,29118,29119,
9506029120,29121,29122,29123,29124,29125,29126,29127,29128,29129,29130,29131,
9506129132,29133,29134,29135,29136,29137,29138,29139,29140,29141,29142,29143,
9506229144,29145,29146,29147,29148,29149,29150,29151,29152,29153,29154,29155,
9506329156,29157,29158,29159,29160,29161,29162,29163,29164,29165,29166,29167,
9506429168,29169,29170,29171,29172,29173,29174,29175,29176,29177,29178,29179,
9506529180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29190,29191,
9506629192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,
9506729204,29205,29206,29207,29208,29209,29210,29211,29212,29213,29214,29215,
9506829216,29217,29218,29219,29220,29221,29222,29223,29224,29225,29226,29227,
9506929228,29229,29230,29231,29232,29233,29234,29235,29236,29237,29238,29239,
9507029240,29241,29242,29243,29244,29245,29246,29247,29248,29249,29250,29251,
9507129252,29253,29254,29255,29256,29257,29258,29259,29260,29261,29262,29263,
9507229264,29265,29266,29267,29268,29269,29270,29271,29272,29273,29274,29275,
9507329276,29277,29278,29279,29280,29281,29282,29283,29284,29285,29286,29287,
9507429288,29289,29290,29291,29292,29293,29294,29295,29296,29297,29298,29299,
9507529300,29301,29302,29303,29304,29305,29306,29307,29308,29309,29310,29311,
9507629312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323,
9507729324,29325,29326,29327,29328,29329,29330,29331,29332,29333,29334,29335,
9507829336,29337,29338,29339,29340,29341,29342,29343,29344,29345,29346,29347,
9507929348,29349,29350,29351,29352,29353,29354,29355,29356,29357,29358,29359,
9508029360,29361,29362,29363,29364,29365,29366,29367,29368,29369,29370,29371,
9508129372,29373,29374,29375,29376,29377,29378,29379,29380,29381,29382,29383,
9508229384,29385,29386,29387,29388,29389,29390,29391,29392,29393,29394,29395,
9508329396,29397,29398,29399,29400,29401,29402,29403,29404,29405,29406,29407,
9508429408,29409,29410,29411,29412,29413,29414,29415,29416,29417,29418,29419,
9508529420,29421,29422,29423,29424,29425,29426,29427,29428,29429,29430,29431,
9508629432,29433,29434,29435,29436,29437,29438,29439,29440,29441,29442,29443,
9508729444,29445,29446,29447,29448,29449,29450,29451,29452,29453,29454,29455,
9508829456,29457,29458,29459,29460,29461,29462,29463,29464,29465,29466,29467,
9508929468,29469,29470,29471,29472,29473,29474,29475,29476,29477,29478,29479,
9509029480,29481,29482,29483,29484,29485,29486,29487,29488,29489,29490,29491,
9509129492,29493,29494,29495,29496,29497,29498,29499,29500,29501,29502,29503,
9509229504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,
9509329516,29517,29518,29519,29520,29521,29522,29523,29524,29525,29526,29527,
9509429528,29529,29530,29531,29532,29533,29534,29535,29536,29537,29538,29539,
9509529540,29541,29542,29543,29544,29545,29546,29547,29548,29549,29550,29551,
9509629552,29553,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,
9509729564,29565,29566,29567,29568,29569,29570,29571,29572,29573,29574,29575,
9509829576,29577,29578,29579,29580,29581,29582,29583,29584,29585,29586,29587,
9509929588,29589,29590,29591,29592,29593,29594,29595,29596,29597,29598,29599,
9510029600,29601,29602,29603,29604,29605,29606,29607,29608,29609,29610,29611,
9510129612,29613,29614,29615,29616,29617,29618,29619,29620,29621,29622,29623,
9510229624,29625,29626,29627,29628,29629,29630,29631,29632,29633,29634,29635,
9510329636,29637,29638,29639,29640,29641,29642,29643,29644,29645,29646,29647,
9510429648,29649,29650,29651,29652,29653,29654,29655,29656,29657,29658,29659,
9510529660,29661,29662,29663,29664,29665,29666,29667,29668,29669,29670,29671,
9510629672,29673,29674,29675,29676,29677,29678,29679,29680,29681,29682,29683,
9510729684,29685,29686,29687,29688,29689,29690,29691,29692,29693,29694,29695,
9510829696,29697,29698,29699,29700,29701,29702,29703,29704,29705,29706,29707,
9510929708,29709,29710,29711,29712,29713,29714,29715,29716,29717,29718,29719,
9511029720,29721,29722,29723,29724,29725,29726,29727,29728,29729,29730,29731,
9511129732,29733,29734,29735,29736,29737,29738,29739,29740,29741,29742,29743,
9511229744,29745,29746,29747,29748,29749,29750,29751,29752,29753,29754,29755,
9511329756,29757,29758,29759,29760,29761,29762,29763,29764,29765,29766,29767,
9511429768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,
9511529780,29781,29782,29783,29784,29785,29786,29787,29788,29789,29790,29791,
9511629792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,
9511729804,29805,29806,29807,29808,29809,29810,29811,29812,29813,29814,29815,
9511829816,29817,29818,29819,29820,29821,29822,29823,29824,29825,29826,29827,
9511929828,29829,29830,29831,29832,29833,29834,29835,29836,29837,29838,29839,
9512029840,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,
9512129852,29853,29854,29855,29856,29857,29858,29859,29860,29861,29862,29863,
9512229864,29865,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,
9512329876,29877,29878,29879,29880,29881,29882,29883,29884,29885,29886,29887,
9512429888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,
9512529900,29901,29902,29903,29904,29905,29906,29907,29908,29909,29910,29911,
9512629912,29913,29914,29915,29916,29917,29918,29919,29920,29921,29922,29923,
9512729924,29925,29926,29927,29928,29929,29930,29931,29932,29933,29934,29935,
9512829936,29937,29938,29939,29940,29941,29942,29943,29944,29945,29946,29947,
9512929948,29949,29950,29951,29952,29953,29954,29955,29956,29957,29958,29959,
9513029960,29961,29962,29963,29964,29965,29966,29967,29968,29969,29970,29971,
9513129972,29973,29974,29975,29976,29977,29978,29979,29980,29981,29982,29983,
9513229984,29985,29986,29987,29988,29989,29990,29991,29992,29993,29994,29995,
9513329996,29997,29998,29999,30000,30001,30002,30003,30004,30005,30006,30007,
9513430008,30009,30010,30011,30012,30013,30014,30015,30016,30017,30018,30019,
9513530020,30021,30022,30023,30024,30025,30026,30027,30028,30029,30030,30031,
9513630032,30033,30034,30035,30036,30037,30038,30039,30040,30041,30042,30043,
9513730044,30045,30046,30047,30048,30049,30050,30051,30052,30053,30054,30055,
9513830056,30057,30058,30059,30060,30061,30062,30063,30064,30065,30066,30067,
9513930068,30069,30070,30071,30072,30073,30074,30075,30076,30077,30078,30079,
9514030080,30081,30082,30083,30084,30085,30086,30087,30088,30089,30090,30091,
9514130092,30093,30094,30095,30096,30097,30098,30099,30100,30101,30102,30103,
9514230104,30105,30106,30107,30108,30109,30110,30111,30112,30113,30114,30115,
9514330116,30117,30118,30119,30120,30121,30122,30123,30124,30125,30126,30127,
9514430128,30129,30130,30131,30132,30133,30134,30135,30136,30137,30138,30139,
9514530140,30141,30142,30143,30144,30145,30146,30147,30148,30149,30150,30151,
9514630152,30153,30154,30155,30156,30157,30158,30159,30160,30161,30162,30163,
9514730164,30165,30166,30167,30168,30169,30170,30171,30172,30173,30174,30175,
9514830176,30177,30178,30179,30180,30181,30182,30183,30184,30185,30186,30187,
9514930188,30189,30190,30191,30192,30193,30194,30195,30196,30197,30198,30199,
9515030200,30201,30202,30203,30204,30205,30206,30207,30208,30209,30210,30211,
9515130212,30213,30214,30215,30216,30217,30218,30219,30220,30221,30222,30223,
9515230224,30225,30226,30227,30228,30229,30230,30231,30232,30233,30234,30235,
9515330236,30237,30238,30239,30240,30241,30242,30243,30244,30245,30246,30247,
9515430248,30249,30250,30251,30252,30253,30254,30255,30256,30257,30258,30259,
9515530260,30261,30262,30263,30264,30265,30266,30267,30268,30269,30270,30271,
9515630272,30273,30274,30275,30276,30277,30278,30279,30280,30281,30282,30283,
9515730284,30285,30286,30287,30288,30289,30290,30291,30292,30293,30294,30295,
9515830296,30297,30298,30299,30300,30301,30302,30303,30304,30305,30306,30307,
9515930308,30309,30310,30311,30312,30313,30314,30315,30316,30317,30318,30319,
9516030320,30321,30322,30323,30324,30325,30326,30327,30328,30329,30330,30331,
9516130332,30333,30334,30335,30336,30337,30338,30339,30340,30341,30342,30343,
9516230344,30345,30346,30347,30348,30349,30350,30351,30352,30353,30354,30355,
9516330356,30357,30358,30359,30360,30361,30362,30363,30364,30365,30366,30367,
9516430368,30369,30370,30371,30372,30373,30374,30375,30376,30377,30378,30379,
9516530380,30381,30382,30383,30384,30385,30386,30387,30388,30389,30390,30391,
9516630392,30393,30394,30395,30396,30397,30398,30399,30400,30401,30402,30403,
9516730404,30405,30406,30407,30408,30409,30410,30411,30412,30413,30414,30415,
9516830416,30417,30418,30419,30420,30421,30422,30423,30424,30425,30426,30427,
9516930428,30429,30430,30431,30432,30433,30434,30435,30436,30437,30438,30439,
9517030440,30441,30442,30443,30444,30445,30446,30447,30448,30449,30450,30451,
9517130452,30453,30454,30455,30456,30457,30458,30459,30460,30461,30462,30463,
9517230464,30465,30466,30467,30468,30469,30470,30471,30472,30473,30474,30475,
9517330476,30477,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,
9517430488,30489,30490,30491,30492,30493,30494,30495,30496,30497,30498,30499,
9517530500,30501,30502,30503,30504,30505,30506,30507,30508,30509,30510,30511,
9517630512,30513,30514,30515,30516,30517,30518,30519,30520,30521,30522,30523,
9517730524,30525,30526,30527,30528,30529,30530,30531,30532,30533,30534,30535,
9517830536,30537,30538,30539,30540,30541,30542,30543,30544,30545,30546,30547,
9517930548,30549,30550,30551,30552,30553,30554,30555,30556,30557,30558,30559,
9518030560,30561,30562,30563,30564,30565,30566,30567,30568,30569,30570,30571,
9518130572,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,
9518230584,30585,30586,30587,30588,30589,30590,30591,30592,30593,30594,30595,
9518330596,30597,30598,30599,30600,30601,30602,30603,30604,30605,30606,30607,
9518430608,30609,30610,30611,30612,30613,30614,30615,30616,30617,30618,30619,
9518530620,30621,30622,30623,30624,30625,30626,30627,30628,30629,30630,30631,
9518630632,30633,30634,30635,30636,30637,30638,30639,30640,30641,30642,30643,
9518730644,30645,30646,30647,30648,30649,30650,30651,30652,30653,30654,30655,
9518830656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,
9518930668,30669,30670,30671,30672,30673,30674,30675,30676,30677,30678,30679,
9519030680,30681,30682,30683,30684,30685,30686,30687,30688,30689,30690,30691,
9519130692,30693,30694,30695,30696,30697,30698,30699,30700,30701,30702,30703,
9519230704,30705,30706,30707,30708,30709,30710,30711,30712,30713,30714,30715,
9519330716,30717,30718,30719,30720,30721,30722,30723,30724,30725,30726,30727,
9519430728,30729,30730,30731,30732,30733,30734,30735,30736,30737,30738,30739,
9519530740,30741,30742,30743,30744,30745,30746,30747,30748,30749,30750,30751,
9519630752,30753,30754,30755,30756,30757,30758,30759,30760,30761,30762,30763,
9519730764,30765,30766,30767,30768,30769,30770,30771,30772,30773,30774,30775,
9519830776,30777,30778,30779,30780,30781,30782,30783,30784,30785,30786,30787,
9519930788,30789,30790,30791,30792,30793,30794,30795,30796,30797,30798,30799,
9520030800,30801,30802,30803,30804,30805,30806,30807,30808,30809,30810,30811,
9520130812,30813,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,
9520230824,30825,30826,30827,30828,30829,30830,30831,30832,30833,30834,30835,
9520330836,30837,30838,30839,30840,30841,30842,30843,30844,30845,30846,30847,
9520430848,30849,30850,30851,30852,30853,30854,30855,30856,30857,30858,30859,
9520530860,30861,30862,30863,30864,30865,30866,30867,30868,30869,30870,30871,
9520630872,30873,30874,30875,30876,30877,30878,30879,30880,30881,30882,30883,
9520730884,30885,30886,30887,30888,30889,30890,30891,30892,30893,30894,30895,
9520830896,30897,30898,30899,30900,30901,30902,30903,30904,30905,30906,30907,
9520930908,30909,30910,30911,30912,30913,30914,30915,30916,30917,30918,30919,
9521030920,30921,30922,30923,30924,30925,30926,30927,30928,30929,30930,30931,
9521130932,30933,30934,30935,30936,30937,30938,30939,30940,30941,30942,30943,
9521230944,30945,30946,30947,30948,30949,30950,30951,30952,30953,30954,30955,
9521330956,30957,30958,30959,30960,30961,30962,30963,30964,30965,30966,30967,
9521430968,30969,30970,30971,30972,30973,30974,30975,30976,30977,30978,30979,
9521530980,30981,30982,30983,30984,30985,30986,30987,30988,30989,30990,30991,
9521630992,30993,30994,30995,30996,30997,30998,30999,31000,31001,31002,31003,
9521731004,31005,31006,31007,31008,31009,31010,31011,31012,31013,31014,31015,
9521831016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,
9521931028,31029,31030,31031,31032,31033,31034,31035,31036,31037,31038,31039,
9522031040,31041,31042,31043,31044,31045,31046,31047,31048,31049,31050,31051,
9522131052,31053,31054,31055,31056,31057,31058,31059,31060,31061,31062,31063,
9522231064,31065,31066,31067,31068,31069,31070,31071,31072,31073,31074,31075,
9522331076,31077,31078,31079,31080,31081,31082,31083,31084,31085,31086,31087,
9522431088,31089,31090,31091,31092,31093,31094,31095,31096,31097,31098,31099,
9522531100,31101,31102,31103,31104,31105,31106,31107,31108,31109,31110,31111,
9522631112,31113,31114,31115,31116,31117,31118,31119,31120,31121,31122,31123,
9522731124,31125,31126,31127,31128,31129,31130,31131,31132,31133,31134,31135,
9522831136,31137,31138,31139,31140,31141,31142,31143,31144,31145,31146,31147,
9522931148,31149,31150,31151,31152,31153,31154,31155,31156,31157,31158,31159,
9523031160,31161,31162,31163,31164,31165,31166,31167,31168,31169,31170,31171,
9523131172,31173,31174,31175,31176,31177,31178,31179,31180,31181,31182,31183,
9523231184,31185,31186,31187,31188,31189,31190,31191,31192,31193,31194,31195,
9523331196,31197,31198,31199,31200,31201,31202,31203,31204,31205,31206,31207,
9523431208,31209,31210,31211,31212,31213,31214,31215,31216,31217,31218,31219,
9523531220,31221,31222,31223,31224,31225,31226,31227,31228,31229,31230,31231,
9523631232,31233,31234,31235,31236,31237,31238,31239,31240,31241,31242,31243,
9523731244,31245,31246,31247,31248,31249,31250,31251,31252,31253,31254,31255,
9523831256,31257,31258,31259,31260,31261,31262,31263,31264,31265,31266,31267,
9523931268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,
9524031280,31281,31282,31283,31284,31285,31286,31287,31288,31289,31290,31291,
9524131292,31293,31294,31295,31296,31297,31298,31299,31300,31301,31302,31303,
9524231304,31305,31306,31307,31308,31309,31310,31311,31312,31313,31314,31315,
9524331316,31317,31318,31319,31320,31321,31322,31323,31324,31325,31326,31327,
9524431328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,
9524531340,31341,31342,31343,31344,31345,31346,31347,31348,31349,31350,31351,
9524631352,31353,31354,31355,31356,31357,31358,31359,31360,31361,31362,31363,
9524731364,31365,31366,31367,31368,31369,31370,31371,31372,31373,31374,31375,
9524831376,31377,31378,31379,31380,31381,31382,31383,31384,31385,31386,31387,
9524931388,31389,31390,31391,31392,31393,31394,31395,31396,31397,31398,31399,
9525031400,31401,31402,31403,31404,31405,31406,31407,31408,31409,31410,31411,
9525131412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31423,
9525231424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31435,
9525331436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31446,31447,
9525431448,31449,31450,31451,31452,31453,31454,31455,31456,31457,31458,31459,
9525531460,31461,31462,31463,31464,31465,31466,31467,31468,31469,31470,31471,
9525631472,31473,31474,31475,31476,31477,31478,31479,31480,31481,31482,31483,
9525731484,31485,31486,31487,31488,31489,31490,31491,31492,31493,31494,31495,
9525831496,31497,31498,31499,31500,31501,31502,31503,31504,31505,31506,31507,
9525931508,31509,31510,31511,31512,31513,31514,31515,31516,31517,31518,31519,
9526031520,31521,31522,31523,31524,31525,31526,31527,31528,31529,31530,31531,
9526131532,31533,31534,31535,31536,31537,31538,31539,31540,31541,31542,31543,
9526231544,31545,31546,31547,31548,31549,31550,31551,31552,31553,31554,31555,
9526331556,31557,31558,31559,31560,31561,31562,31563,31564,31565,31566,31567,
9526431568,31569,31570,31571,31572,31573,31574,31575,31576,31577,31578,31579,
9526531580,31581,31582,31583,31584,31585,31586,31587,31588,31589,31590,31591,
9526631592,31593,31594,31595,31596,31597,31598,31599,31600,31601,31602,31603,
9526731604,31605,31606,31607,31608,31609,31610,31611,31612,31613,31614,31615,
9526831616,31617,31618,31619,31620,31621,31622,31623,31624,31625,31626,31627,
9526931628,31629,31630,31631,31632,31633,31634,31635,31636,31637,31638,31639,
9527031640,31641,31642,31643,31644,31645,31646,31647,31648,31649,31650,31651,
9527131652,31653,31654,31655,31656,31657,31658,31659,31660,31661,31662,31663,
9527231664,31665,31666,31667,31668,31669,31670,31671,31672,31673,31674,31675,
9527331676,31677,31678,31679,31680,31681,31682,31683,31684,31685,31686,31687,
9527431688,31689,31690,31691,31692,31693,31694,31695,31696,31697,31698,31699,
9527531700,31701,31702,31703,31704,31705,31706,31707,31708,31709,31710,31711,
9527631712,31713,31714,31715,31716,31717,31718,31719,31720,31721,31722,31723,
9527731724,31725,31726,31727,31728,31729,31730,31731,31732,31733,31734,31735,
9527831736,31737,31738,31739,31740,31741,31742,31743,31744,31745,31746,31747,
9527931748,31749,31750,31751,31752,31753,31754,31755,31756,31757,31758,31759,
9528031760,31761,31762,31763,31764,31765,31766,31767,31768,31769,31770,31771,
9528131772,31773,31774,31775,31776,31777,31778,31779,31780,31781,31782,31783,
9528231784,31785,31786,31787,31788,31789,31790,31791,31792,31793,31794,31795,
9528331796,31797,31798,31799,31800,31801,31802,31803,31804,31805,31806,31807,
9528431808,31809,31810,31811,31812,31813,31814,31815,31816,31817,31818,31819,
9528531820,31821,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,
9528631832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,
9528731844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,
9528831856,31857,31858,31859,31860,31861,31862,31863,31864,31865,31866,31867,
9528931868,31869,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,
9529031880,31881,31882,31883,31884,31885,31886,31887,31888,31889,31890,31891,
9529131892,31893,31894,31895,31896,31897,31898,31899,31900,31901,31902,31903,
9529231904,31905,31906,31907,31908,31909,31910,31911,31912,31913,31914,31915,
9529331916,31917,31918,31919,31920,31921,31922,31923,31924,31925,31926,31927,
9529431928,31929,31930,31931,31932,31933,31934,31935,31936,31937,31938,31939,
9529531940,31941,31942,31943,31944,31945,31946,31947,31948,31949,31950,31951,
9529631952,31953,31954,31955,31956,31957,31958,31959,31960,31961,31962,31963,
9529731964,31965,31966,31967,31968,31969,31970,31971,31972,31973,31974,31975,
9529831976,31977,31978,31979,31980,31981,31982,31983,31984,31985,31986,31987,
9529931988,31989,31990,31991,31992,31993,31994,31995,31996,31997,31998,31999,
9530032000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32010,32011,
9530132012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,
9530232024,32025,32026,32027,32028,32029,32030,32031,32032,32033,32034,32035,
9530332036,32037,32038,32039,32040,32041,32042,32043,32044,32045,32046,32047,
9530432048,32049,32050,32051,32052,32053,32054,32055,32056,32057,32058,32059,
9530532060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,
9530632072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,
9530732084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,
9530832096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,
9530932108,32109,32110,32111,32112,32113,32114,32115,32116,32117,32118,32119,
9531032120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,
9531132132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,
9531232144,32145,32146,32147,32148,32149,32150,32151,32152,32153,32154,32155,
9531332156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32166,32167,
9531432168,32169,32170,32171,32172,32173,32174,32175,32176,32177,32178,32179,
9531532180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,
9531632192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,
9531732204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,
9531832216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,
9531932228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,
9532032240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,32251,
9532132252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,
9532232264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,
9532332276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,
9532432288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,
9532532300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,
9532632312,32313,32314,32315,32316,32317,32318,32319,32320,32321,32322,32323,
9532732324,32325,32326,32327,32328,32329,32330,32331,32332,32333,32334,32335,
9532832336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,
9532932348,32349,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,
9533032360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,
9533132372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,
9533232384,32385,32386,32387,32388,32389,32390,32391,32392,32393,32394,32395,
9533332396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,
9533432408,32409,32410,32411,32412,32413,32414,32415,32416,32417,32418,32419,
9533532420,32421,32422,32423,32424,32425,32426,32427,32428,32429,32430,32431,
9533632432,32433,32434,32435,32436,32437,32438,32439,32440,32441,32442,32443,
9533732444,32445,32446,32447,32448,32449,32450,32451,32452,32453,32454,32455,
9533832456,32457,32458,32459,32460,32461,32462,32463,32464,32465,32466,32467,
9533932468,32469,32470,32471,32472,32473,32474,32475,32476,32477,32478,32479,
9534032480,32481,32482,32483,32484,32485,32486,32487,32488,32489,32490,32491,
9534132492,32493,32494,32495,32496,32497,32498,32499,32500,32501,32502,32503,
9534232504,32505,32506,32507,32508,32509,32510,32511,32512,32513,32514,32515,
9534332516,32517,32518,32519,32520,32521,32522,32523,32524,32525,32526,32527,
9534432528,32529,32530,32531,32532,32533,32534,32535,32536,32537,32538,32539,
9534532540,32541,32542,32543,32544,32545,32546,32547,32548,32549,32550,32551,
9534632552,32553,32554,32555,32556,32557,32558,32559,32560,32561,32562,32563,
9534732564,32565,32566,32567,32568,32569,32570,32571,32572,32573,32574,32575,
9534832576,32577,32578,32579,32580,32581,32582,32583,32584,32585,32586,32587,
9534932588,32589,32590,32591,32592,32593,32594,32595,32596,32597,32598,32599,
9535032600,32601,32602,32603,32604,32605,32606,32607,32608,32609,32610,32611,
9535132612,32613,32614,32615,32616,32617,32618,32619,32620,32621,32622,32623,
9535232624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635,
9535332636,32637,32638,32639,32640,32641,32642,32643,32644,32645,32646,32647,
9535432648,32649,32650,32651,32652,32653,32654,32655,32656,32657,32658,32659,
9535532660,32661,32662,32663,32664,32665,32666,32667,32668,32669,32670,32671,
9535632672,32673,32674,32675,32676,32677,32678,32679,32680,32681,32682,32683,
9535732684,32685,32686,32687,32688,32689,32690,32691,32692,32693,32694,32695,
9535832696,32697,32698,32699,32700,32701,32702,32703,32704,32705,32706,32707,
9535932708,32709,32710,32711,32712,32713,32714,32715,32716,32717,32718,32719,
9536032720,32721,32722,32723,32724,32725,32726,32727,32728,32729,32730,32731,
9536132732,32733,32734,32735,32736,32737,32738,32739,32740,32741,32742,32743,
9536232744,32745,32746,32747,32748,32749,32750,32751,32752,32753,32754,32755,
9536332756,32757,32758,32759,32760,32761,32762,32763,32764,32765,32766,32767,
9536432768L,32769L,32770L,32771L,32772L,32773L,32774L,32775L,32776L,32777L,
9536532778L,32779L,32780L,32781L,32782L,32783L,32784L,32785L,32786L,32787L,
9536632788L,32789L,32790L,32791L,32792L,32793L,32794L,32795L,32796L,32797L,
9536732798L,32799L,32800L,32801L,32802L,32803L,32804L,32805L,32806L,32807L,
9536832808L,32809L,32810L,32811L,32812L,32813L,32814L,32815L,32816L,32817L,
9536932818L,32819L,32820L,32821L,32822L,32823L,32824L,32825L,32826L,32827L,
9537032828L,32829L,32830L,32831L,32832L,32833L,32834L,32835L,32836L,32837L,
9537132838L,32839L,32840L,32841L,32842L,32843L,32844L,32845L,32846L,32847L,
9537232848L,32849L,32850L,32851L,32852L,32853L,32854L,32855L,32856L,32857L,
9537332858L,32859L,32860L,32861L,32862L,32863L,32864L,32865L,32866L,32867L,
9537432868L,32869L,32870L,32871L,32872L,32873L,32874L,32875L,32876L,32877L,
9537532878L,32879L,32880L,32881L,32882L,32883L,32884L,32885L,32886L,32887L,
9537632888L,32889L,32890L,32891L,32892L,32893L,32894L,32895L,32896L,32897L,
9537732898L,32899L,32900L,32901L,32902L,32903L,32904L,32905L,32906L,32907L,
9537832908L,32909L,32910L,32911L,32912L,32913L,32914L,32915L,32916L,32917L,
9537932918L,32919L,32920L,32921L,32922L,32923L,32924L,32925L,32926L,32927L,
9538032928L,32929L,32930L,32931L,32932L,32933L,32934L,32935L,32936L,32937L,
9538132938L,32939L,32940L,32941L,32942L,32943L,32944L,32945L,32946L,32947L,
9538232948L,32949L,32950L,32951L,32952L,32953L,32954L,32955L,32956L,32957L,
9538332958L,32959L,32960L,32961L,32962L,32963L,32964L,32965L,32966L,32967L,
9538432968L,32969L,32970L,32971L,32972L,32973L,32974L,32975L,32976L,32977L,
9538532978L,32979L,32980L,32981L,32982L,32983L,32984L,32985L,32986L,32987L,
9538632988L,32989L,32990L,32991L,32992L,32993L,32994L,32995L,32996L,32997L,
9538732998L,32999L,33000L,33001L,33002L,33003L,33004L,33005L,33006L,33007L,
9538833008L,33009L,33010L,33011L,33012L,33013L,33014L,33015L,33016L,33017L,
9538933018L,33019L,33020L,33021L,33022L,33023L,33024L,33025L,33026L,33027L,
9539033028L,33029L,33030L,33031L,33032L,33033L,33034L,33035L,33036L,33037L,
9539133038L,33039L,33040L,33041L,33042L,33043L,33044L,33045L,33046L,33047L,
9539233048L,33049L,33050L,33051L,33052L,33053L,33054L,33055L,33056L,33057L,
9539333058L,33059L,33060L,33061L,33062L,33063L,33064L,33065L,33066L,33067L,
9539433068L,33069L,33070L,33071L,33072L,33073L,33074L,33075L,33076L,33077L,
9539533078L,33079L,33080L,33081L,33082L,33083L,33084L,33085L,33086L,33087L,
9539633088L,33089L,33090L,33091L,33092L,33093L,33094L,33095L,33096L,33097L,
9539733098L,33099L,33100L,33101L,33102L,33103L,33104L,33105L,33106L,33107L,
9539833108L,33109L,33110L,33111L,33112L,33113L,33114L,33115L,33116L,33117L,
9539933118L,33119L,33120L,33121L,33122L,33123L,33124L,33125L,33126L,33127L,
9540033128L,33129L,33130L,33131L,33132L,33133L,33134L,33135L,33136L,33137L,
9540133138L,33139L,33140L,33141L,33142L,33143L,33144L,33145L,33146L,33147L,
9540233148L,33149L,33150L,33151L,33152L,33153L,33154L,33155L,33156L,33157L,
9540333158L,33159L,33160L,33161L,33162L,33163L,33164L,33165L,33166L,33167L,
9540433168L,33169L,33170L,33171L,33172L,33173L,33174L,33175L,33176L,33177L,
9540533178L,33179L,33180L,33181L,33182L,33183L,33184L,33185L,33186L,33187L,
9540633188L,33189L,33190L,33191L,33192L,33193L,33194L,33195L,33196L,33197L,
9540733198L,33199L,33200L,33201L,33202L,33203L,33204L,33205L,33206L,33207L,
9540833208L,33209L,33210L,33211L,33212L,33213L,33214L,33215L,33216L,33217L,
9540933218L,33219L,33220L,33221L,33222L,33223L,33224L,33225L,33226L,33227L,
9541033228L,33229L,33230L,33231L,33232L,33233L,33234L,33235L,33236L,33237L,
9541133238L,33239L,33240L,33241L,33242L,33243L,33244L,33245L,33246L,33247L,
9541233248L,33249L,33250L,33251L,33252L,33253L,33254L,33255L,33256L,33257L,
9541333258L,33259L,33260L,33261L,33262L,33263L,33264L,33265L,33266L,33267L,
9541433268L,33269L,33270L,33271L,33272L,33273L,33274L,33275L,33276L,33277L,
9541533278L,33279L,33280L,33281L,33282L,33283L,33284L,33285L,33286L,33287L,
9541633288L,33289L,33290L,33291L,33292L,33293L,33294L,33295L,33296L,33297L,
9541733298L,33299L,33300L,33301L,33302L,33303L,33304L,33305L,33306L,33307L,
9541833308L,33309L,33310L,33311L,33312L,33313L,33314L,33315L,33316L,33317L,
9541933318L,33319L,33320L,33321L,33322L,33323L,33324L,33325L,33326L,33327L,
9542033328L,33329L,33330L,33331L,33332L,33333L,33334L,33335L,33336L,33337L,
9542133338L,33339L,33340L,33341L,33342L,33343L,33344L,33345L,33346L,33347L,
9542233348L,33349L,33350L,33351L,33352L,33353L,33354L,33355L,33356L,33357L,
9542333358L,33359L,33360L,33361L,33362L,33363L,33364L,33365L,33366L,33367L,
9542433368L,33369L,33370L,33371L,33372L,33373L,33374L,33375L,33376L,33377L,
9542533378L,33379L,33380L,33381L,33382L,33383L,33384L,33385L,33386L,33387L,
9542633388L,33389L,33390L,33391L,33392L,33393L,33394L,33395L,33396L,33397L,
9542733398L,33399L,33400L,33401L,33402L,33403L,33404L,33405L,33406L,33407L,
9542833408L,33409L,33410L,33411L,33412L,33413L,33414L,33415L,33416L,33417L,
9542933418L,33419L,33420L,33421L,33422L,33423L,33424L,33425L,33426L,33427L,
9543033428L,33429L,33430L,33431L,33432L,33433L,33434L,33435L,33436L,33437L,
9543133438L,33439L,33440L,33441L,33442L,33443L,33444L,33445L,33446L,33447L,
9543233448L,33449L,33450L,33451L,33452L,33453L,33454L,33455L,33456L,33457L,
9543333458L,33459L,33460L,33461L,33462L,33463L,33464L,33465L,33466L,33467L,
9543433468L,33469L,33470L,33471L,33472L,33473L,33474L,33475L,33476L,33477L,
9543533478L,33479L,33480L,33481L,33482L,33483L,33484L,33485L,33486L,33487L,
9543633488L,33489L,33490L,33491L,33492L,33493L,33494L,33495L,33496L,33497L,
9543733498L,33499L,33500L,33501L,33502L,33503L,33504L,33505L,33506L,33507L,
9543833508L,33509L,33510L,33511L,33512L,33513L,33514L,33515L,33516L,33517L,
9543933518L,33519L,33520L,33521L,33522L,33523L,33524L,33525L,33526L,33527L,
9544033528L,33529L,33530L,33531L,33532L,33533L,33534L,33535L,33536L,33537L,
9544133538L,33539L,33540L,33541L,33542L,33543L,33544L,33545L,33546L,33547L,
9544233548L,33549L,33550L,33551L,33552L,33553L,33554L,33555L,33556L,33557L,
9544333558L,33559L,33560L,33561L,33562L,33563L,33564L,33565L,33566L,33567L,
9544433568L,33569L,33570L,33571L,33572L,33573L,33574L,33575L,33576L,33577L,
9544533578L,33579L,33580L,33581L,33582L,33583L,33584L,33585L,33586L,33587L,
9544633588L,33589L,33590L,33591L,33592L,33593L,33594L,33595L,33596L,33597L,
9544733598L,33599L,33600L,33601L,33602L,33603L,33604L,33605L,33606L,33607L,
9544833608L,33609L,33610L,33611L,33612L,33613L,33614L,33615L,33616L,33617L,
9544933618L,33619L,33620L,33621L,33622L,33623L,33624L,33625L,33626L,33627L,
9545033628L,33629L,33630L,33631L,33632L,33633L,33634L,33635L,33636L,33637L,
9545133638L,33639L,33640L,33641L,33642L,33643L,33644L,33645L,33646L,33647L,
9545233648L,33649L,33650L,33651L,33652L,33653L,33654L,33655L,33656L,33657L,
9545333658L,33659L,33660L,33661L,33662L,33663L,33664L,33665L,33666L,33667L,
9545433668L,33669L,33670L,33671L,33672L,33673L,33674L,33675L,33676L,33677L,
9545533678L,33679L,33680L,33681L,33682L,33683L,33684L,33685L,33686L,33687L,
9545633688L,33689L,33690L,33691L,33692L,33693L,33694L,33695L,33696L,33697L,
9545733698L,33699L,33700L,33701L,33702L,33703L,33704L,33705L,33706L,33707L,
9545833708L,33709L,33710L,33711L,33712L,33713L,33714L,33715L,33716L,33717L,
9545933718L,33719L,33720L,33721L,33722L,33723L,33724L,33725L,33726L,33727L,
9546033728L,33729L,33730L,33731L,33732L,33733L,33734L,33735L,33736L,33737L,
9546133738L,33739L,33740L,33741L,33742L,33743L,33744L,33745L,33746L,33747L,
9546233748L,33749L,33750L,33751L,33752L,33753L,33754L,33755L,33756L,33757L,
9546333758L,33759L,33760L,33761L,33762L,33763L,33764L,33765L,33766L,33767L,
9546433768L,33769L,33770L,33771L,33772L,33773L,33774L,33775L,33776L,33777L,
9546533778L,33779L,33780L,33781L,33782L,33783L,33784L,33785L,33786L,33787L,
9546633788L,33789L,33790L,33791L,33792L,33793L,33794L,33795L,33796L,33797L,
9546733798L,33799L,33800L,33801L,33802L,33803L,33804L,33805L,33806L,33807L,
9546833808L,33809L,33810L,33811L,33812L,33813L,33814L,33815L,33816L,33817L,
9546933818L,33819L,33820L,33821L,33822L,33823L,33824L,33825L,33826L,33827L,
9547033828L,33829L,33830L,33831L,33832L,33833L,33834L,33835L,33836L,33837L,
9547133838L,33839L,33840L,33841L,33842L,33843L,33844L,33845L,33846L,33847L,
9547233848L,33849L,33850L,33851L,33852L,33853L,33854L,33855L,33856L,33857L,
9547333858L,33859L,33860L,33861L,33862L,33863L,33864L,33865L,33866L,33867L,
9547433868L,33869L,33870L,33871L,33872L,33873L,33874L,33875L,33876L,33877L,
9547533878L,33879L,33880L,33881L,33882L,33883L,33884L,33885L,33886L,33887L,
9547633888L,33889L,33890L,33891L,33892L,33893L,33894L,33895L,33896L,33897L,
9547733898L,33899L,33900L,33901L,33902L,33903L,33904L,33905L,33906L,33907L,
9547833908L,33909L,33910L,33911L,33912L,33913L,33914L,33915L,33916L,33917L,
9547933918L,33919L,33920L,33921L,33922L,33923L,33924L,33925L,33926L,33927L,
9548033928L,33929L,33930L,33931L,33932L,33933L,33934L,33935L,33936L,33937L,
9548133938L,33939L,33940L,33941L,33942L,33943L,33944L,33945L,33946L,33947L,
9548233948L,33949L,33950L,33951L,33952L,33953L,33954L,33955L,33956L,33957L,
9548333958L,33959L,33960L,33961L,33962L,33963L,33964L,33965L,33966L,33967L,
9548433968L,33969L,33970L,33971L,33972L,33973L,33974L,33975L,33976L,33977L,
9548533978L,33979L,33980L,33981L,33982L,33983L,33984L,33985L,33986L,33987L,
9548633988L,33989L,33990L,33991L,33992L,33993L,33994L,33995L,33996L,33997L,
9548733998L,33999L,34000L,34001L,34002L,34003L,34004L,34005L,34006L,34007L,
9548834008L,34009L,34010L,34011L,34012L,34013L,34014L,34015L,34016L,34017L,
9548934018L,34019L,34020L,34021L,34022L,34023L,34024L,34025L,34026L,34027L,
9549034028L,34029L,34030L,34031L,34032L,34033L,34034L,34035L,34036L,34037L,
9549134038L,34039L,34040L,34041L,34042L,34043L,34044L,34045L,34046L,34047L,
9549234048L,34049L,34050L,34051L,34052L,34053L,34054L,34055L,34056L,34057L,
9549334058L,34059L,34060L,34061L,34062L,34063L,34064L,34065L,34066L,34067L,
9549434068L,34069L,34070L,34071L,34072L,34073L,34074L,34075L,34076L,34077L,
9549534078L,34079L,34080L,34081L,34082L,34083L,34084L,34085L,34086L,34087L,
9549634088L,34089L,34090L,34091L,34092L,34093L,34094L,34095L,34096L,34097L,
9549734098L,34099L,34100L,34101L,34102L,34103L,34104L,34105L,34106L,34107L,
9549834108L,34109L,34110L,34111L,34112L,34113L,34114L,34115L,34116L,34117L,
9549934118L,34119L,34120L,34121L,34122L,34123L,34124L,34125L,34126L,34127L,
9550034128L,34129L,34130L,34131L,34132L,34133L,34134L,34135L,34136L,34137L,
9550134138L,34139L,34140L,34141L,34142L,34143L,34144L,34145L,34146L,34147L,
9550234148L,34149L,34150L,34151L,34152L,34153L,34154L,34155L,34156L,34157L,
9550334158L,34159L,34160L,34161L,34162L,34163L,34164L,34165L,34166L,34167L,
9550434168L,34169L,34170L,34171L,34172L,34173L,34174L,34175L,34176L,34177L,
9550534178L,34179L,34180L,34181L,34182L,34183L,34184L,34185L,34186L,34187L,
9550634188L,34189L,34190L,34191L,34192L,34193L,34194L,34195L,34196L,34197L,
9550734198L,34199L,34200L,34201L,34202L,34203L,34204L,34205L,34206L,34207L,
9550834208L,34209L,34210L,34211L,34212L,34213L,34214L,34215L,34216L,34217L,
9550934218L,34219L,34220L,34221L,34222L,34223L,34224L,34225L,34226L,34227L,
9551034228L,34229L,34230L,34231L,34232L,34233L,34234L,34235L,34236L,34237L,
9551134238L,34239L,34240L,34241L,34242L,34243L,34244L,34245L,34246L,34247L,
9551234248L,34249L,34250L,34251L,34252L,34253L,34254L,34255L,34256L,34257L,
9551334258L,34259L,34260L,34261L,34262L,34263L,34264L,34265L,34266L,34267L,
9551434268L,34269L,34270L,34271L,34272L,34273L,34274L,34275L,34276L,34277L,
9551534278L,34279L,34280L,34281L,34282L,34283L,34284L,34285L,34286L,34287L,
9551634288L,34289L,34290L,34291L,34292L,34293L,34294L,34295L,34296L,34297L,
9551734298L,34299L,34300L,34301L,34302L,34303L,34304L,34305L,34306L,34307L,
9551834308L,34309L,34310L,34311L,34312L,34313L,34314L,34315L,34316L,34317L,
9551934318L,34319L,34320L,34321L,34322L,34323L,34324L,34325L,34326L,34327L,
9552034328L,34329L,34330L,34331L,34332L,34333L,34334L,34335L,34336L,34337L,
9552134338L,34339L,34340L,34341L,34342L,34343L,34344L,34345L,34346L,34347L,
9552234348L,34349L,34350L,34351L,34352L,34353L,34354L,34355L,34356L,34357L,
9552334358L,34359L,34360L,34361L,34362L,34363L,34364L,34365L,34366L,34367L,
9552434368L,34369L,34370L,34371L,34372L,34373L,34374L,34375L,34376L,34377L,
9552534378L,34379L,34380L,34381L,34382L,34383L,34384L,34385L,34386L,34387L,
9552634388L,34389L,34390L,34391L,34392L,34393L,34394L,34395L,34396L,34397L,
9552734398L,34399L,34400L,34401L,34402L,34403L,34404L,34405L,34406L,34407L,
9552834408L,34409L,34410L,34411L,34412L,34413L,34414L,34415L,34416L,34417L,
9552934418L,34419L,34420L,34421L,34422L,34423L,34424L,34425L,34426L,34427L,
9553034428L,34429L,34430L,34431L,34432L,34433L,34434L,34435L,34436L,34437L,
9553134438L,34439L,34440L,34441L,34442L,34443L,34444L,34445L,34446L,34447L,
9553234448L,34449L,34450L,34451L,34452L,34453L,34454L,34455L,34456L,34457L,
9553334458L,34459L,34460L,34461L,34462L,34463L,34464L,34465L,34466L,34467L,
9553434468L,34469L,34470L,34471L,34472L,34473L,34474L,34475L,34476L,34477L,
9553534478L,34479L,34480L,34481L,34482L,34483L,34484L,34485L,34486L,34487L,
9553634488L,34489L,34490L,34491L,34492L,34493L,34494L,34495L,34496L,34497L,
9553734498L,34499L,34500L,34501L,34502L,34503L,34504L,34505L,34506L,34507L,
9553834508L,34509L,34510L,34511L,34512L,34513L,34514L,34515L,34516L,34517L,
9553934518L,34519L,34520L,34521L,34522L,34523L,34524L,34525L,34526L,34527L,
9554034528L,34529L,34530L,34531L,34532L,34533L,34534L,34535L,34536L,34537L,
9554134538L,34539L,34540L,34541L,34542L,34543L,34544L,34545L,34546L,34547L,
9554234548L,34549L,34550L,34551L,34552L,34553L,34554L,34555L,34556L,34557L,
9554334558L,34559L,34560L,34561L,34562L,34563L,34564L,34565L,34566L,34567L,
9554434568L,34569L,34570L,34571L,34572L,34573L,34574L,34575L,34576L,34577L,
9554534578L,34579L,34580L,34581L,34582L,34583L,34584L,34585L,34586L,34587L,
9554634588L,34589L,34590L,34591L,34592L,34593L,34594L,34595L,34596L,34597L,
9554734598L,34599L,34600L,34601L,34602L,34603L,34604L,34605L,34606L,34607L,
9554834608L,34609L,34610L,34611L,34612L,34613L,34614L,34615L,34616L,34617L,
9554934618L,34619L,34620L,34621L,34622L,34623L,34624L,34625L,34626L,34627L,
9555034628L,34629L,34630L,34631L,34632L,34633L,34634L,34635L,34636L,34637L,
9555134638L,34639L,34640L,34641L,34642L,34643L,34644L,34645L,34646L,34647L,
9555234648L,34649L,34650L,34651L,34652L,34653L,34654L,34655L,34656L,34657L,
9555334658L,34659L,34660L,34661L,34662L,34663L,34664L,34665L,34666L,34667L,
9555434668L,34669L,34670L,34671L,34672L,34673L,34674L,34675L,34676L,34677L,
9555534678L,34679L,34680L,34681L,34682L,34683L,34684L,34685L,34686L,34687L,
9555634688L,34689L,34690L,34691L,34692L,34693L,34694L,34695L,34696L,34697L,
9555734698L,34699L,34700L,34701L,34702L,34703L,34704L,34705L,34706L,34707L,
9555834708L,34709L,34710L,34711L,34712L,34713L,34714L,34715L,34716L,34717L,
9555934718L,34719L,34720L,34721L,34722L,34723L,34724L,34725L,34726L,34727L,
9556034728L,34729L,34730L,34731L,34732L,34733L,34734L,34735L,34736L,34737L,
9556134738L,34739L,34740L,34741L,34742L,34743L,34744L,34745L,34746L,34747L,
9556234748L,34749L,34750L,34751L,34752L,34753L,34754L,34755L,34756L,34757L,
9556334758L,34759L,34760L,34761L,34762L,34763L,34764L,34765L,34766L,34767L,
9556434768L,34769L,34770L,34771L,34772L,34773L,34774L,34775L,34776L,34777L,
9556534778L,34779L,34780L,34781L,34782L,34783L,34784L,34785L,34786L,34787L,
9556634788L,34789L,34790L,34791L,34792L,34793L,34794L,34795L,34796L,34797L,
9556734798L,34799L,34800L,34801L,34802L,34803L,34804L,34805L,34806L,34807L,
9556834808L,34809L,34810L,34811L,34812L,34813L,34814L,34815L,34816L,34817L,
9556934818L,34819L,34820L,34821L,34822L,34823L,34824L,34825L,34826L,34827L,
9557034828L,34829L,34830L,34831L,34832L,34833L,34834L,34835L,34836L,34837L,
9557134838L,34839L,34840L,34841L,34842L,34843L,34844L,34845L,34846L,34847L,
9557234848L,34849L,34850L,34851L,34852L,34853L,34854L,34855L,34856L,34857L,
9557334858L,34859L,34860L,34861L,34862L,34863L,34864L,34865L,34866L,34867L,
9557434868L,34869L,34870L,34871L,34872L,34873L,34874L,34875L,34876L,34877L,
9557534878L,34879L,34880L,34881L,34882L,34883L,34884L,34885L,34886L,34887L,
9557634888L,34889L,34890L,34891L,34892L,34893L,34894L,34895L,34896L,34897L,
9557734898L,34899L,34900L,34901L,34902L,34903L,34904L,34905L,34906L,34907L,
9557834908L,34909L,34910L,34911L,34912L,34913L,34914L,34915L,34916L,34917L,
9557934918L,34919L,34920L,34921L,34922L,34923L,34924L,34925L,34926L,34927L,
9558034928L,34929L,34930L,34931L,34932L,34933L,34934L,34935L,34936L,34937L,
9558134938L,34939L,34940L,34941L,34942L,34943L,34944L,34945L,34946L,34947L,
9558234948L,34949L,34950L,34951L,34952L,34953L,34954L,34955L,34956L,34957L,
9558334958L,34959L,34960L,34961L,34962L,34963L,34964L,34965L,34966L,34967L,
9558434968L,34969L,34970L,34971L,34972L,34973L,34974L,34975L,34976L,34977L,
9558534978L,34979L,34980L,34981L,34982L,34983L,34984L,34985L,34986L,34987L,
9558634988L,34989L,34990L,34991L,34992L,34993L,34994L,34995L,34996L,34997L,
9558734998L,34999L,35000L,35001L,35002L,35003L,35004L,35005L,35006L,35007L,
9558835008L,35009L,35010L,35011L,35012L,35013L,35014L,35015L,35016L,35017L,
9558935018L,35019L,35020L,35021L,35022L,35023L,35024L,35025L,35026L,35027L,
9559035028L,35029L,35030L,35031L,35032L,35033L,35034L,35035L,35036L,35037L,
9559135038L,35039L,35040L,35041L,35042L,35043L,35044L,35045L,35046L,35047L,
9559235048L,35049L,35050L,35051L,35052L,35053L,35054L,35055L,35056L,35057L,
9559335058L,35059L,35060L,35061L,35062L,35063L,35064L,35065L,35066L,35067L,
9559435068L,35069L,35070L,35071L,35072L,35073L,35074L,35075L,35076L,35077L,
9559535078L,35079L,35080L,35081L,35082L,35083L,35084L,35085L,35086L,35087L,
9559635088L,35089L,35090L,35091L,35092L,35093L,35094L,35095L,35096L,35097L,
9559735098L,35099L,35100L,35101L,35102L,35103L,35104L,35105L,35106L,35107L,
9559835108L,35109L,35110L,35111L,35112L,35113L,35114L,35115L,35116L,35117L,
9559935118L,35119L,35120L,35121L,35122L,35123L,35124L,35125L,35126L,35127L,
9560035128L,35129L,35130L,35131L,35132L,35133L,35134L,35135L,35136L,35137L,
9560135138L,35139L,35140L,35141L,35142L,35143L,35144L,35145L,35146L,35147L,
9560235148L,35149L,35150L,35151L,35152L,35153L,35154L,35155L,35156L,35157L,
9560335158L,35159L,35160L,35161L,35162L,35163L,35164L,35165L,35166L,35167L,
9560435168L,35169L,35170L,35171L,35172L,35173L,35174L,35175L,35176L,35177L,
9560535178L,35179L,35180L,35181L,35182L,35183L,35184L,35185L,35186L,35187L,
9560635188L,35189L,35190L,35191L,35192L,35193L,35194L,35195L,35196L,35197L,
9560735198L,35199L,35200L,35201L,35202L,35203L,35204L,35205L,35206L,35207L,
9560835208L,35209L,35210L,35211L,35212L,35213L,35214L,35215L,35216L,35217L,
9560935218L,35219L,35220L,35221L,35222L,35223L,35224L,35225L,35226L,35227L,
9561035228L,35229L,35230L,35231L,35232L,35233L,35234L,35235L,35236L,35237L,
9561135238L,35239L,35240L,35241L,35242L,35243L,35244L,35245L,35246L,35247L,
9561235248L,35249L,35250L,35251L,35252L,35253L,35254L,35255L,35256L,35257L,
9561335258L,35259L,35260L,35261L,35262L,35263L,35264L,35265L,35266L,35267L,
9561435268L,35269L,35270L,35271L,35272L,35273L,35274L,35275L,35276L,35277L,
9561535278L,35279L,35280L,35281L,35282L,35283L,35284L,35285L,35286L,35287L,
9561635288L,35289L,35290L,35291L,35292L,35293L,35294L,35295L,35296L,35297L,
9561735298L,35299L,35300L,35301L,35302L,35303L,35304L,35305L,35306L,35307L,
9561835308L,35309L,35310L,35311L,35312L,35313L,35314L,35315L,35316L,35317L,
9561935318L,35319L,35320L,35321L,35322L,35323L,35324L,35325L,35326L,35327L,
9562035328L,35329L,35330L,35331L,35332L,35333L,35334L,35335L,35336L,35337L,
9562135338L,35339L,35340L,35341L,35342L,35343L,35344L,35345L,35346L,35347L,
9562235348L,35349L,35350L,35351L,35352L,35353L,35354L,35355L,35356L,35357L,
9562335358L,35359L,35360L,35361L,35362L,35363L,35364L,35365L,35366L,35367L,
9562435368L,35369L,35370L,35371L,35372L,35373L,35374L,35375L,35376L,35377L,
9562535378L,35379L,35380L,35381L,35382L,35383L,35384L,35385L,35386L,35387L,
9562635388L,35389L,35390L,35391L,35392L,35393L,35394L,35395L,35396L,35397L,
9562735398L,35399L,35400L,35401L,35402L,35403L,35404L,35405L,35406L,35407L,
9562835408L,35409L,35410L,35411L,35412L,35413L,35414L,35415L,35416L,35417L,
9562935418L,35419L,35420L,35421L,35422L,35423L,35424L,35425L,35426L,35427L,
9563035428L,35429L,35430L,35431L,35432L,35433L,35434L,35435L,35436L,35437L,
9563135438L,35439L,35440L,35441L,35442L,35443L,35444L,35445L,35446L,35447L,
9563235448L,35449L,35450L,35451L,35452L,35453L,35454L,35455L,35456L,35457L,
9563335458L,35459L,35460L,35461L,35462L,35463L,35464L,35465L,35466L,35467L,
9563435468L,35469L,35470L,35471L,35472L,35473L,35474L,35475L,35476L,35477L,
9563535478L,35479L,35480L,35481L,35482L,35483L,35484L,35485L,35486L,35487L,
9563635488L,35489L,35490L,35491L,35492L,35493L,35494L,35495L,35496L,35497L,
9563735498L,35499L,35500L,35501L,35502L,35503L,35504L,35505L,35506L,35507L,
9563835508L,35509L,35510L,35511L,35512L,35513L,35514L,35515L,35516L,35517L,
9563935518L,35519L,35520L,35521L,35522L,35523L,35524L,35525L,35526L,35527L,
9564035528L,35529L,35530L,35531L,35532L,35533L,35534L,35535L,35536L,35537L,
9564135538L,35539L,35540L,35541L,35542L,35543L,35544L,35545L,35546L,35547L,
9564235548L,35549L,35550L,35551L,35552L,35553L,35554L,35555L,35556L,35557L,
9564335558L,35559L,35560L,35561L,35562L,35563L,35564L,35565L,35566L,35567L,
9564435568L,35569L,35570L,35571L,35572L,35573L,35574L,35575L,35576L,35577L,
9564535578L,35579L,35580L,35581L,35582L,35583L,35584L,35585L,35586L,35587L,
9564635588L,35589L,35590L,35591L,35592L,35593L,35594L,35595L,35596L,35597L,
9564735598L,35599L,35600L,35601L,35602L,35603L,35604L,35605L,35606L,35607L,
9564835608L,35609L,35610L,35611L,35612L,35613L,35614L,35615L,35616L,35617L,
9564935618L,35619L,35620L,35621L,35622L,35623L,35624L,35625L,35626L,35627L,
9565035628L,35629L,35630L,35631L,35632L,35633L,35634L,35635L,35636L,35637L,
9565135638L,35639L,35640L,35641L,35642L,35643L,35644L,35645L,35646L,35647L,
9565235648L,35649L,35650L,35651L,35652L,35653L,35654L,35655L,35656L,35657L,
9565335658L,35659L,35660L,35661L,35662L,35663L,35664L,35665L,35666L,35667L,
9565435668L,35669L,35670L,35671L,35672L,35673L,35674L,35675L,35676L,35677L,
9565535678L,35679L,35680L,35681L,35682L,35683L,35684L,35685L,35686L,35687L,
9565635688L,35689L,35690L,35691L,35692L,35693L,35694L,35695L,35696L,35697L,
9565735698L,35699L,35700L,35701L,35702L,35703L,35704L,35705L,35706L,35707L,
9565835708L,35709L,35710L,35711L,35712L,35713L,35714L,35715L,35716L,35717L,
9565935718L,35719L,35720L,35721L,35722L,35723L,35724L,35725L,35726L,35727L,
9566035728L,35729L,35730L,35731L,35732L,35733L,35734L,35735L,35736L,35737L,
9566135738L,35739L,35740L,35741L,35742L,35743L,35744L,35745L,35746L,35747L,
9566235748L,35749L,35750L,35751L,35752L,35753L,35754L,35755L,35756L,35757L,
9566335758L,35759L,35760L,35761L,35762L,35763L,35764L,35765L,35766L,35767L,
9566435768L,35769L,35770L,35771L,35772L,35773L,35774L,35775L,35776L,35777L,
9566535778L,35779L,35780L,35781L,35782L,35783L,35784L,35785L,35786L,35787L,
9566635788L,35789L,35790L,35791L,35792L,35793L,35794L,35795L,35796L,35797L,
9566735798L,35799L,35800L,35801L,35802L,35803L,35804L,35805L,35806L,35807L,
9566835808L,35809L,35810L,35811L,35812L,35813L,35814L,35815L,35816L,35817L,
9566935818L,35819L,35820L,35821L,35822L,35823L,35824L,35825L,35826L,35827L,
9567035828L,35829L,35830L,35831L,35832L,35833L,35834L,35835L,35836L,35837L,
9567135838L,35839L,35840L,35841L,35842L,35843L,35844L,35845L,35846L,35847L,
9567235848L,35849L,35850L,35851L,35852L,35853L,35854L,35855L,35856L,35857L,
9567335858L,35859L,35860L,35861L,35862L,35863L,35864L,35865L,35866L,35867L,
9567435868L,35869L,35870L,35871L,35872L,35873L,35874L,35875L,35876L,35877L,
9567535878L,35879L,35880L,35881L,35882L,35883L,35884L,35885L,35886L,35887L,
9567635888L,35889L,35890L,35891L,35892L,35893L,35894L,35895L,35896L,35897L,
9567735898L,35899L,35900L,35901L,35902L,35903L,35904L,35905L,35906L,35907L,
9567835908L,35909L,35910L,35911L,35912L,35913L,35914L,35915L,35916L,35917L,
9567935918L,35919L,35920L,35921L,35922L,35923L,35924L,35925L,35926L,35927L,
9568035928L,35929L,35930L,35931L,35932L,35933L,35934L,35935L,35936L,35937L,
9568135938L,35939L,35940L,35941L,35942L,35943L,35944L,35945L,35946L,35947L,
9568235948L,35949L,35950L,35951L,35952L,35953L,35954L,35955L,35956L,35957L,
9568335958L,35959L,35960L,35961L,35962L,35963L,35964L,35965L,35966L,35967L,
9568435968L,35969L,35970L,35971L,35972L,35973L,35974L,35975L,35976L,35977L,
9568535978L,35979L,35980L,35981L,35982L,35983L,35984L,35985L,35986L,35987L,
9568635988L,35989L,35990L,35991L,35992L,35993L,35994L,35995L,35996L,35997L,
9568735998L,35999L,36000L,36001L,36002L,36003L,36004L,36005L,36006L,36007L,
9568836008L,36009L,36010L,36011L,36012L,36013L,36014L,36015L,36016L,36017L,
9568936018L,36019L,36020L,36021L,36022L,36023L,36024L,36025L,36026L,36027L,
9569036028L,36029L,36030L,36031L,36032L,36033L,36034L,36035L,36036L,36037L,
9569136038L,36039L,36040L,36041L,36042L,36043L,36044L,36045L,36046L,36047L,
9569236048L,36049L,36050L,36051L,36052L,36053L,36054L,36055L,36056L,36057L,
9569336058L,36059L,36060L,36061L,36062L,36063L,36064L,36065L,36066L,36067L,
9569436068L,36069L,36070L,36071L,36072L,36073L,36074L,36075L,36076L,36077L,
9569536078L,36079L,36080L,36081L,36082L,36083L,36084L,36085L,36086L,36087L,
9569636088L,36089L,36090L,36091L,36092L,36093L,36094L,36095L,36096L,36097L,
9569736098L,36099L,36100L,36101L,36102L,36103L,36104L,36105L,36106L,36107L,
9569836108L,36109L,36110L,36111L,36112L,36113L,36114L,36115L,36116L,36117L,
9569936118L,36119L,36120L,36121L,36122L,36123L,36124L,36125L,36126L,36127L,
9570036128L,36129L,36130L,36131L,36132L,36133L,36134L,36135L,36136L,36137L,
9570136138L,36139L,36140L,36141L,36142L,36143L,36144L,36145L,36146L,36147L,
9570236148L,36149L,36150L,36151L,36152L,36153L,36154L,36155L,36156L,36157L,
9570336158L,36159L,36160L,36161L,36162L,36163L,36164L,36165L,36166L,36167L,
9570436168L,36169L,36170L,36171L,36172L,36173L,36174L,36175L,36176L,36177L,
9570536178L,36179L,36180L,36181L,36182L,36183L,36184L,36185L,36186L,36187L,
9570636188L,36189L,36190L,36191L,36192L,36193L,36194L,36195L,36196L,36197L,
9570736198L,36199L,36200L,36201L,36202L,36203L,36204L,36205L,36206L,36207L,
9570836208L,36209L,36210L,36211L,36212L,36213L,36214L,36215L,36216L,36217L,
9570936218L,36219L,36220L,36221L,36222L,36223L,36224L,36225L,36226L,36227L,
9571036228L,36229L,36230L,36231L,36232L,36233L,36234L,36235L,36236L,36237L,
9571136238L,36239L,36240L,36241L,36242L,36243L,36244L,36245L,36246L,36247L,
9571236248L,36249L,36250L,36251L,36252L,36253L,36254L,36255L,36256L,36257L,
9571336258L,36259L,36260L,36261L,36262L,36263L,36264L,36265L,36266L,36267L,
9571436268L,36269L,36270L,36271L,36272L,36273L,36274L,36275L,36276L,36277L,
9571536278L,36279L,36280L,36281L,36282L,36283L,36284L,36285L,36286L,36287L,
9571636288L,36289L,36290L,36291L,36292L,36293L,36294L,36295L,36296L,36297L,
9571736298L,36299L,36300L,36301L,36302L,36303L,36304L,36305L,36306L,36307L,
9571836308L,36309L,36310L,36311L,36312L,36313L,36314L,36315L,36316L,36317L,
9571936318L,36319L,36320L,36321L,36322L,36323L,36324L,36325L,36326L,36327L,
9572036328L,36329L,36330L,36331L,36332L,36333L,36334L,36335L,36336L,36337L,
9572136338L,36339L,36340L,36341L,36342L,36343L,36344L,36345L,36346L,36347L,
9572236348L,36349L,36350L,36351L,36352L,36353L,36354L,36355L,36356L,36357L,
9572336358L,36359L,36360L,36361L,36362L,36363L,36364L,36365L,36366L,36367L,
9572436368L,36369L,36370L,36371L,36372L,36373L,36374L,36375L,36376L,36377L,
9572536378L,36379L,36380L,36381L,36382L,36383L,36384L,36385L,36386L,36387L,
9572636388L,36389L,36390L,36391L,36392L,36393L,36394L,36395L,36396L,36397L,
9572736398L,36399L,36400L,36401L,36402L,36403L,36404L,36405L,36406L,36407L,
9572836408L,36409L,36410L,36411L,36412L,36413L,36414L,36415L,36416L,36417L,
9572936418L,36419L,36420L,36421L,36422L,36423L,36424L,36425L,36426L,36427L,
9573036428L,36429L,36430L,36431L,36432L,36433L,36434L,36435L,36436L,36437L,
9573136438L,36439L,36440L,36441L,36442L,36443L,36444L,36445L,36446L,36447L,
9573236448L,36449L,36450L,36451L,36452L,36453L,36454L,36455L,36456L,36457L,
9573336458L,36459L,36460L,36461L,36462L,36463L,36464L,36465L,36466L,36467L,
9573436468L,36469L,36470L,36471L,36472L,36473L,36474L,36475L,36476L,36477L,
9573536478L,36479L,36480L,36481L,36482L,36483L,36484L,36485L,36486L,36487L,
9573636488L,36489L,36490L,36491L,36492L,36493L,36494L,36495L,36496L,36497L,
9573736498L,36499L,36500L,36501L,36502L,36503L,36504L,36505L,36506L,36507L,
9573836508L,36509L,36510L,36511L,36512L,36513L,36514L,36515L,36516L,36517L,
9573936518L,36519L,36520L,36521L,36522L,36523L,36524L,36525L,36526L,36527L,
9574036528L,36529L,36530L,36531L,36532L,36533L,36534L,36535L,36536L,36537L,
9574136538L,36539L,36540L,36541L,36542L,36543L,36544L,36545L,36546L,36547L,
9574236548L,36549L,36550L,36551L,36552L,36553L,36554L,36555L,36556L,36557L,
9574336558L,36559L,36560L,36561L,36562L,36563L,36564L,36565L,36566L,36567L,
9574436568L,36569L,36570L,36571L,36572L,36573L,36574L,36575L,36576L,36577L,
9574536578L,36579L,36580L,36581L,36582L,36583L,36584L,36585L,36586L,36587L,
9574636588L,36589L,36590L,36591L,36592L,36593L,36594L,36595L,36596L,36597L,
9574736598L,36599L,36600L,36601L,36602L,36603L,36604L,36605L,36606L,36607L,
9574836608L,36609L,36610L,36611L,36612L,36613L,36614L,36615L,36616L,36617L,
9574936618L,36619L,36620L,36621L,36622L,36623L,36624L,36625L,36626L,36627L,
9575036628L,36629L,36630L,36631L,36632L,36633L,36634L,36635L,36636L,36637L,
9575136638L,36639L,36640L,36641L,36642L,36643L,36644L,36645L,36646L,36647L,
9575236648L,36649L,36650L,36651L,36652L,36653L,36654L,36655L,36656L,36657L,
9575336658L,36659L,36660L,36661L,36662L,36663L,36664L,36665L,36666L,36667L,
9575436668L,36669L,36670L,36671L,36672L,36673L,36674L,36675L,36676L,36677L,
9575536678L,36679L,36680L,36681L,36682L,36683L,36684L,36685L,36686L,36687L,
9575636688L,36689L,36690L,36691L,36692L,36693L,36694L,36695L,36696L,36697L,
9575736698L,36699L,36700L,36701L,36702L,36703L,36704L,36705L,36706L,36707L,
9575836708L,36709L,36710L,36711L,36712L,36713L,36714L,36715L,36716L,36717L,
9575936718L,36719L,36720L,36721L,36722L,36723L,36724L,36725L,36726L,36727L,
9576036728L,36729L,36730L,36731L,36732L,36733L,36734L,36735L,36736L,36737L,
9576136738L,36739L,36740L,36741L,36742L,36743L,36744L,36745L,36746L,36747L,
9576236748L,36749L,36750L,36751L,36752L,36753L,36754L,36755L,36756L,36757L,
9576336758L,36759L,36760L,36761L,36762L,36763L,36764L,36765L,36766L,36767L,
9576436768L,36769L,36770L,36771L,36772L,36773L,36774L,36775L,36776L,36777L,
9576536778L,36779L,36780L,36781L,36782L,36783L,36784L,36785L,36786L,36787L,
9576636788L,36789L,36790L,36791L,36792L,36793L,36794L,36795L,36796L,36797L,
9576736798L,36799L,36800L,36801L,36802L,36803L,36804L,36805L,36806L,36807L,
9576836808L,36809L,36810L,36811L,36812L,36813L,36814L,36815L,36816L,36817L,
9576936818L,36819L,36820L,36821L,36822L,36823L,36824L,36825L,36826L,36827L,
9577036828L,36829L,36830L,36831L,36832L,36833L,36834L,36835L,36836L,36837L,
9577136838L,36839L,36840L,36841L,36842L,36843L,36844L,36845L,36846L,36847L,
9577236848L,36849L,36850L,36851L,36852L,36853L,36854L,36855L,36856L,36857L,
9577336858L,36859L,36860L,36861L,36862L,36863L,36864L,36865L,36866L,36867L,
9577436868L,36869L,36870L,36871L,36872L,36873L,36874L,36875L,36876L,36877L,
9577536878L,36879L,36880L,36881L,36882L,36883L,36884L,36885L,36886L,36887L,
9577636888L,36889L,36890L,36891L,36892L,36893L,36894L,36895L,36896L,36897L,
9577736898L,36899L,36900L,36901L,36902L,36903L,36904L,36905L,36906L,36907L,
9577836908L,36909L,36910L,36911L,36912L,36913L,36914L,36915L,36916L,36917L,
9577936918L,36919L,36920L,36921L,36922L,36923L,36924L,36925L,36926L,36927L,
9578036928L,36929L,36930L,36931L,36932L,36933L,36934L,36935L,36936L,36937L,
9578136938L,36939L,36940L,36941L,36942L,36943L,36944L,36945L,36946L,36947L,
9578236948L,36949L,36950L,36951L,36952L,36953L,36954L,36955L,36956L,36957L,
9578336958L,36959L,36960L,36961L,36962L,36963L,36964L,36965L,36966L,36967L,
9578436968L,36969L,36970L,36971L,36972L,36973L,36974L,36975L,36976L,36977L,
9578536978L,36979L,36980L,36981L,36982L,36983L,36984L,36985L,36986L,36987L,
9578636988L,36989L,36990L,36991L,36992L,36993L,36994L,36995L,36996L,36997L,
9578736998L,36999L,37000L,37001L,37002L,37003L,37004L,37005L,37006L,37007L,
9578837008L,37009L,37010L,37011L,37012L,37013L,37014L,37015L,37016L,37017L,
9578937018L,37019L,37020L,37021L,37022L,37023L,37024L,37025L,37026L,37027L,
9579037028L,37029L,37030L,37031L,37032L,37033L,37034L,37035L,37036L,37037L,
9579137038L,37039L,37040L,37041L,37042L,37043L,37044L,37045L,37046L,37047L,
9579237048L,37049L,37050L,37051L,37052L,37053L,37054L,37055L,37056L,37057L,
9579337058L,37059L,37060L,37061L,37062L,37063L,37064L,37065L,37066L,37067L,
9579437068L,37069L,37070L,37071L,37072L,37073L,37074L,37075L,37076L,37077L,
9579537078L,37079L,37080L,37081L,37082L,37083L,37084L,37085L,37086L,37087L,
9579637088L,37089L,37090L,37091L,37092L,37093L,37094L,37095L,37096L,37097L,
9579737098L,37099L,37100L,37101L,37102L,37103L,37104L,37105L,37106L,37107L,
9579837108L,37109L,37110L,37111L,37112L,37113L,37114L,37115L,37116L,37117L,
9579937118L,37119L,37120L,37121L,37122L,37123L,37124L,37125L,37126L,37127L,
9580037128L,37129L,37130L,37131L,37132L,37133L,37134L,37135L,37136L,37137L,
9580137138L,37139L,37140L,37141L,37142L,37143L,37144L,37145L,37146L,37147L,
9580237148L,37149L,37150L,37151L,37152L,37153L,37154L,37155L,37156L,37157L,
9580337158L,37159L,37160L,37161L,37162L,37163L,37164L,37165L,37166L,37167L,
9580437168L,37169L,37170L,37171L,37172L,37173L,37174L,37175L,37176L,37177L,
9580537178L,37179L,37180L,37181L,37182L,37183L,37184L,37185L,37186L,37187L,
9580637188L,37189L,37190L,37191L,37192L,37193L,37194L,37195L,37196L,37197L,
9580737198L,37199L,37200L,37201L,37202L,37203L,37204L,37205L,37206L,37207L,
9580837208L,37209L,37210L,37211L,37212L,37213L,37214L,37215L,37216L,37217L,
9580937218L,37219L,37220L,37221L,37222L,37223L,37224L,37225L,37226L,37227L,
9581037228L,37229L,37230L,37231L,37232L,37233L,37234L,37235L,37236L,37237L,
9581137238L,37239L,37240L,37241L,37242L,37243L,37244L,37245L,37246L,37247L,
9581237248L,37249L,37250L,37251L,37252L,37253L,37254L,37255L,37256L,37257L,
9581337258L,37259L,37260L,37261L,37262L,37263L,37264L,37265L,37266L,37267L,
9581437268L,37269L,37270L,37271L,37272L,37273L,37274L,37275L,37276L,37277L,
9581537278L,37279L,37280L,37281L,37282L,37283L,37284L,37285L,37286L,37287L,
9581637288L,37289L,37290L,37291L,37292L,37293L,37294L,37295L,37296L,37297L,
9581737298L,37299L,37300L,37301L,37302L,37303L,37304L,37305L,37306L,37307L,
9581837308L,37309L,37310L,37311L,37312L,37313L,37314L,37315L,37316L,37317L,
9581937318L,37319L,37320L,37321L,37322L,37323L,37324L,37325L,37326L,37327L,
9582037328L,37329L,37330L,37331L,37332L,37333L,37334L,37335L,37336L,37337L,
9582137338L,37339L,37340L,37341L,37342L,37343L,37344L,37345L,37346L,37347L,
9582237348L,37349L,37350L,37351L,37352L,37353L,37354L,37355L,37356L,37357L,
9582337358L,37359L,37360L,37361L,37362L,37363L,37364L,37365L,37366L,37367L,
9582437368L,37369L,37370L,37371L,37372L,37373L,37374L,37375L,37376L,37377L,
9582537378L,37379L,37380L,37381L,37382L,37383L,37384L,37385L,37386L,37387L,
9582637388L,37389L,37390L,37391L,37392L,37393L,37394L,37395L,37396L,37397L,
9582737398L,37399L,37400L,37401L,37402L,37403L,37404L,37405L,37406L,37407L,
9582837408L,37409L,37410L,37411L,37412L,37413L,37414L,37415L,37416L,37417L,
9582937418L,37419L,37420L,37421L,37422L,37423L,37424L,37425L,37426L,37427L,
9583037428L,37429L,37430L,37431L,37432L,37433L,37434L,37435L,37436L,37437L,
9583137438L,37439L,37440L,37441L,37442L,37443L,37444L,37445L,37446L,37447L,
9583237448L,37449L,37450L,37451L,37452L,37453L,37454L,37455L,37456L,37457L,
9583337458L,37459L,37460L,37461L,37462L,37463L,37464L,37465L,37466L,37467L,
9583437468L,37469L,37470L,37471L,37472L,37473L,37474L,37475L,37476L,37477L,
9583537478L,37479L,37480L,37481L,37482L,37483L,37484L,37485L,37486L,37487L,
9583637488L,37489L,37490L,37491L,37492L,37493L,37494L,37495L,37496L,37497L,
9583737498L,37499L,37500L,37501L,37502L,37503L,37504L,37505L,37506L,37507L,
9583837508L,37509L,37510L,37511L,37512L,37513L,37514L,37515L,37516L,37517L,
9583937518L,37519L,37520L,37521L,37522L,37523L,37524L,37525L,37526L,37527L,
9584037528L,37529L,37530L,37531L,37532L,37533L,37534L,37535L,37536L,37537L,
9584137538L,37539L,37540L,37541L,37542L,37543L,37544L,37545L,37546L,37547L,
9584237548L,37549L,37550L,37551L,37552L,37553L,37554L,37555L,37556L,37557L,
9584337558L,37559L,37560L,37561L,37562L,37563L,37564L,37565L,37566L,37567L,
9584437568L,37569L,37570L,37571L,37572L,37573L,37574L,37575L,37576L,37577L,
9584537578L,37579L,37580L,37581L,37582L,37583L,37584L,37585L,37586L,37587L,
9584637588L,37589L,37590L,37591L,37592L,37593L,37594L,37595L,37596L,37597L,
9584737598L,37599L,37600L,37601L,37602L,37603L,37604L,37605L,37606L,37607L,
9584837608L,37609L,37610L,37611L,37612L,37613L,37614L,37615L,37616L,37617L,
9584937618L,37619L,37620L,37621L,37622L,37623L,37624L,37625L,37626L,37627L,
9585037628L,37629L,37630L,37631L,37632L,37633L,37634L,37635L,37636L,37637L,
9585137638L,37639L,37640L,37641L,37642L,37643L,37644L,37645L,37646L,37647L,
9585237648L,37649L,37650L,37651L,37652L,37653L,37654L,37655L,37656L,37657L,
9585337658L,37659L,37660L,37661L,37662L,37663L,37664L,37665L,37666L,37667L,
9585437668L,37669L,37670L,37671L,37672L,37673L,37674L,37675L,37676L,37677L,
9585537678L,37679L,37680L,37681L,37682L,37683L,37684L,37685L,37686L,37687L,
9585637688L,37689L,37690L,37691L,37692L,37693L,37694L,37695L,37696L,37697L,
9585737698L,37699L,37700L,37701L,37702L,37703L,37704L,37705L,37706L,37707L,
9585837708L,37709L,37710L,37711L,37712L,37713L,37714L,37715L,37716L,37717L,
9585937718L,37719L,37720L,37721L,37722L,37723L,37724L,37725L,37726L,37727L,
9586037728L,37729L,37730L,37731L,37732L,37733L,37734L,37735L,37736L,37737L,
9586137738L,37739L,37740L,37741L,37742L,37743L,37744L,37745L,37746L,37747L,
9586237748L,37749L,37750L,37751L,37752L,37753L,37754L,37755L,37756L,37757L,
9586337758L,37759L,37760L,37761L,37762L,37763L,37764L,37765L,37766L,37767L,
9586437768L,37769L,37770L,37771L,37772L,37773L,37774L,37775L,37776L,37777L,
9586537778L,37779L,37780L,37781L,37782L,37783L,37784L,37785L,37786L,37787L,
9586637788L,37789L,37790L,37791L,37792L,37793L,37794L,37795L,37796L,37797L,
9586737798L,37799L,37800L,37801L,37802L,37803L,37804L,37805L,37806L,37807L,
9586837808L,37809L,37810L,37811L,37812L,37813L,37814L,37815L,37816L,37817L,
9586937818L,37819L,37820L,37821L,37822L,37823L,37824L,37825L,37826L,37827L,
9587037828L,37829L,37830L,37831L,37832L,37833L,37834L,37835L,37836L,37837L,
9587137838L,37839L,37840L,37841L,37842L,37843L,37844L,37845L,37846L,37847L,
9587237848L,37849L,37850L,37851L,37852L,37853L,37854L,37855L,37856L,37857L,
9587337858L,37859L,37860L,37861L,37862L,37863L,37864L,37865L,37866L,37867L,
9587437868L,37869L,37870L,37871L,37872L,37873L,37874L,37875L,37876L,37877L,
9587537878L,37879L,37880L,37881L,37882L,37883L,37884L,37885L,37886L,37887L,
9587637888L,37889L,37890L,37891L,37892L,37893L,37894L,37895L,37896L,37897L,
9587737898L,37899L,37900L,37901L,37902L,37903L,37904L,37905L,37906L,37907L,
9587837908L,37909L,37910L,37911L,37912L,37913L,37914L,37915L,37916L,37917L,
9587937918L,37919L,37920L,37921L,37922L,37923L,37924L,37925L,37926L,37927L,
9588037928L,37929L,37930L,37931L,37932L,37933L,37934L,37935L,37936L,37937L,
9588137938L,37939L,37940L,37941L,37942L,37943L,37944L,37945L,37946L,37947L,
9588237948L,37949L,37950L,37951L,37952L,37953L,37954L,37955L,37956L,37957L,
9588337958L,37959L,37960L,37961L,37962L,37963L,37964L,37965L,37966L,37967L,
9588437968L,37969L,37970L,37971L,37972L,37973L,37974L,37975L,37976L,37977L,
9588537978L,37979L,37980L,37981L,37982L,37983L,37984L,37985L,37986L,37987L,
9588637988L,37989L,37990L,37991L,37992L,37993L,37994L,37995L,37996L,37997L,
9588737998L,37999L,38000L,38001L,38002L,38003L,38004L,38005L,38006L,38007L,
9588838008L,38009L,38010L,38011L,38012L,38013L,38014L,38015L,38016L,38017L,
9588938018L,38019L,38020L,38021L,38022L,38023L,38024L,38025L,38026L,38027L,
9589038028L,38029L,38030L,38031L,38032L,38033L,38034L,38035L,38036L,38037L,
9589138038L,38039L,38040L,38041L,38042L,38043L,38044L,38045L,38046L,38047L,
9589238048L,38049L,38050L,38051L,38052L,38053L,38054L,38055L,38056L,38057L,
9589338058L,38059L,38060L,38061L,38062L,38063L,38064L,38065L,38066L,38067L,
9589438068L,38069L,38070L,38071L,38072L,38073L,38074L,38075L,38076L,38077L,
9589538078L,38079L,38080L,38081L,38082L,38083L,38084L,38085L,38086L,38087L,
9589638088L,38089L,38090L,38091L,38092L,38093L,38094L,38095L,38096L,38097L,
9589738098L,38099L,38100L,38101L,38102L,38103L,38104L,38105L,38106L,38107L,
9589838108L,38109L,38110L,38111L,38112L,38113L,38114L,38115L,38116L,38117L,
9589938118L,38119L,38120L,38121L,38122L,38123L,38124L,38125L,38126L,38127L,
9590038128L,38129L,38130L,38131L,38132L,38133L,38134L,38135L,38136L,38137L,
9590138138L,38139L,38140L,38141L,38142L,38143L,38144L,38145L,38146L,38147L,
9590238148L,38149L,38150L,38151L,38152L,38153L,38154L,38155L,38156L,38157L,
9590338158L,38159L,38160L,38161L,38162L,38163L,38164L,38165L,38166L,38167L,
9590438168L,38169L,38170L,38171L,38172L,38173L,38174L,38175L,38176L,38177L,
9590538178L,38179L,38180L,38181L,38182L,38183L,38184L,38185L,38186L,38187L,
9590638188L,38189L,38190L,38191L,38192L,38193L,38194L,38195L,38196L,38197L,
9590738198L,38199L,38200L,38201L,38202L,38203L,38204L,38205L,38206L,38207L,
9590838208L,38209L,38210L,38211L,38212L,38213L,38214L,38215L,38216L,38217L,
9590938218L,38219L,38220L,38221L,38222L,38223L,38224L,38225L,38226L,38227L,
9591038228L,38229L,38230L,38231L,38232L,38233L,38234L,38235L,38236L,38237L,
9591138238L,38239L,38240L,38241L,38242L,38243L,38244L,38245L,38246L,38247L,
9591238248L,38249L,38250L,38251L,38252L,38253L,38254L,38255L,38256L,38257L,
9591338258L,38259L,38260L,38261L,38262L,38263L,38264L,38265L,38266L,38267L,
9591438268L,38269L,38270L,38271L,38272L,38273L,38274L,38275L,38276L,38277L,
9591538278L,38279L,38280L,38281L,38282L,38283L,38284L,38285L,38286L,38287L,
9591638288L,38289L,38290L,38291L,38292L,38293L,38294L,38295L,38296L,38297L,
9591738298L,38299L,38300L,38301L,38302L,38303L,38304L,38305L,38306L,38307L,
9591838308L,38309L,38310L,38311L,38312L,38313L,38314L,38315L,38316L,38317L,
9591938318L,38319L,38320L,38321L,38322L,38323L,38324L,38325L,38326L,38327L,
9592038328L,38329L,38330L,38331L,38332L,38333L,38334L,38335L,38336L,38337L,
9592138338L,38339L,38340L,38341L,38342L,38343L,38344L,38345L,38346L,38347L,
9592238348L,38349L,38350L,38351L,38352L,38353L,38354L,38355L,38356L,38357L,
9592338358L,38359L,38360L,38361L,38362L,38363L,38364L,38365L,38366L,38367L,
9592438368L,38369L,38370L,38371L,38372L,38373L,38374L,38375L,38376L,38377L,
9592538378L,38379L,38380L,38381L,38382L,38383L,38384L,38385L,38386L,38387L,
9592638388L,38389L,38390L,38391L,38392L,38393L,38394L,38395L,38396L,38397L,
9592738398L,38399L,38400L,38401L,38402L,38403L,38404L,38405L,38406L,38407L,
9592838408L,38409L,38410L,38411L,38412L,38413L,38414L,38415L,38416L,38417L,
9592938418L,38419L,38420L,38421L,38422L,38423L,38424L,38425L,38426L,38427L,
9593038428L,38429L,38430L,38431L,38432L,38433L,38434L,38435L,38436L,38437L,
9593138438L,38439L,38440L,38441L,38442L,38443L,38444L,38445L,38446L,38447L,
9593238448L,38449L,38450L,38451L,38452L,38453L,38454L,38455L,38456L,38457L,
9593338458L,38459L,38460L,38461L,38462L,38463L,38464L,38465L,38466L,38467L,
9593438468L,38469L,38470L,38471L,38472L,38473L,38474L,38475L,38476L,38477L,
9593538478L,38479L,38480L,38481L,38482L,38483L,38484L,38485L,38486L,38487L,
9593638488L,38489L,38490L,38491L,38492L,38493L,38494L,38495L,38496L,38497L,
9593738498L,38499L,38500L,38501L,38502L,38503L,38504L,38505L,38506L,38507L,
9593838508L,38509L,38510L,38511L,38512L,38513L,38514L,38515L,38516L,38517L,
9593938518L,38519L,38520L,38521L,38522L,38523L,38524L,38525L,38526L,38527L,
9594038528L,38529L,38530L,38531L,38532L,38533L,38534L,38535L,38536L,38537L,
9594138538L,38539L,38540L,38541L,38542L,38543L,38544L,38545L,38546L,38547L,
9594238548L,38549L,38550L,38551L,38552L,38553L,38554L,38555L,38556L,38557L,
9594338558L,38559L,38560L,38561L,38562L,38563L,38564L,38565L,38566L,38567L,
9594438568L,38569L,38570L,38571L,38572L,38573L,38574L,38575L,38576L,38577L,
9594538578L,38579L,38580L,38581L,38582L,38583L,38584L,38585L,38586L,38587L,
9594638588L,38589L,38590L,38591L,38592L,38593L,38594L,38595L,38596L,38597L,
9594738598L,38599L,38600L,38601L,38602L,38603L,38604L,38605L,38606L,38607L,
9594838608L,38609L,38610L,38611L,38612L,38613L,38614L,38615L,38616L,38617L,
9594938618L,38619L,38620L,38621L,38622L,38623L,38624L,38625L,38626L,38627L,
9595038628L,38629L,38630L,38631L,38632L,38633L,38634L,38635L,38636L,38637L,
9595138638L,38639L,38640L,38641L,38642L,38643L,38644L,38645L,38646L,38647L,
9595238648L,38649L,38650L,38651L,38652L,38653L,38654L,38655L,38656L,38657L,
9595338658L,38659L,38660L,38661L,38662L,38663L,38664L,38665L,38666L,38667L,
9595438668L,38669L,38670L,38671L,38672L,38673L,38674L,38675L,38676L,38677L,
9595538678L,38679L,38680L,38681L,38682L,38683L,38684L,38685L,38686L,38687L,
9595638688L,38689L,38690L,38691L,38692L,38693L,38694L,38695L,38696L,38697L,
9595738698L,38699L,38700L,38701L,38702L,38703L,38704L,38705L,38706L,38707L,
9595838708L,38709L,38710L,38711L,38712L,38713L,38714L,38715L,38716L,38717L,
9595938718L,38719L,38720L,38721L,38722L,38723L,38724L,38725L,38726L,38727L,
9596038728L,38729L,38730L,38731L,38732L,38733L,38734L,38735L,38736L,38737L,
9596138738L,38739L,38740L,38741L,38742L,38743L,38744L,38745L,38746L,38747L,
9596238748L,38749L,38750L,38751L,38752L,38753L,38754L,38755L,38756L,38757L,
9596338758L,38759L,38760L,38761L,38762L,38763L,38764L,38765L,38766L,38767L,
9596438768L,38769L,38770L,38771L,38772L,38773L,38774L,38775L,38776L,38777L,
9596538778L,38779L,38780L,38781L,38782L,38783L,38784L,38785L,38786L,38787L,
9596638788L,38789L,38790L,38791L,38792L,38793L,38794L,38795L,38796L,38797L,
9596738798L,38799L,38800L,38801L,38802L,38803L,38804L,38805L,38806L,38807L,
9596838808L,38809L,38810L,38811L,38812L,38813L,38814L,38815L,38816L,38817L,
9596938818L,38819L,38820L,38821L,38822L,38823L,38824L,38825L,38826L,38827L,
9597038828L,38829L,38830L,38831L,38832L,38833L,38834L,38835L,38836L,38837L,
9597138838L,38839L,38840L,38841L,38842L,38843L,38844L,38845L,38846L,38847L,
9597238848L,38849L,38850L,38851L,38852L,38853L,38854L,38855L,38856L,38857L,
9597338858L,38859L,38860L,38861L,38862L,38863L,38864L,38865L,38866L,38867L,
9597438868L,38869L,38870L,38871L,38872L,38873L,38874L,38875L,38876L,38877L,
9597538878L,38879L,38880L,38881L,38882L,38883L,38884L,38885L,38886L,38887L,
9597638888L,38889L,38890L,38891L,38892L,38893L,38894L,38895L,38896L,38897L,
9597738898L,38899L,38900L,38901L,38902L,38903L,38904L,38905L,38906L,38907L,
9597838908L,38909L,38910L,38911L,38912L,38913L,38914L,38915L,38916L,38917L,
9597938918L,38919L,38920L,38921L,38922L,38923L,38924L,38925L,38926L,38927L,
9598038928L,38929L,38930L,38931L,38932L,38933L,38934L,38935L,38936L,38937L,
9598138938L,38939L,38940L,38941L,38942L,38943L,38944L,38945L,38946L,38947L,
9598238948L,38949L,38950L,38951L,38952L,38953L,38954L,38955L,38956L,38957L,
9598338958L,38959L,38960L,38961L,38962L,38963L,38964L,38965L,38966L,38967L,
9598438968L,38969L,38970L,38971L,38972L,38973L,38974L,38975L,38976L,38977L,
9598538978L,38979L,38980L,38981L,38982L,38983L,38984L,38985L,38986L,38987L,
9598638988L,38989L,38990L,38991L,38992L,38993L,38994L,38995L,38996L,38997L,
9598738998L,38999L,39000L,39001L,39002L,39003L,39004L,39005L,39006L,39007L,
9598839008L,39009L,39010L,39011L,39012L,39013L,39014L,39015L,39016L,39017L,
9598939018L,39019L,39020L,39021L,39022L,39023L,39024L,39025L,39026L,39027L,
9599039028L,39029L,39030L,39031L,39032L,39033L,39034L,39035L,39036L,39037L,
9599139038L,39039L,39040L,39041L,39042L,39043L,39044L,39045L,39046L,39047L,
9599239048L,39049L,39050L,39051L,39052L,39053L,39054L,39055L,39056L,39057L,
9599339058L,39059L,39060L,39061L,39062L,39063L,39064L,39065L,39066L,39067L,
9599439068L,39069L,39070L,39071L,39072L,39073L,39074L,39075L,39076L,39077L,
9599539078L,39079L,39080L,39081L,39082L,39083L,39084L,39085L,39086L,39087L,
9599639088L,39089L,39090L,39091L,39092L,39093L,39094L,39095L,39096L,39097L,
9599739098L,39099L,39100L,39101L,39102L,39103L,39104L,39105L,39106L,39107L,
9599839108L,39109L,39110L,39111L,39112L,39113L,39114L,39115L,39116L,39117L,
9599939118L,39119L,39120L,39121L,39122L,39123L,39124L,39125L,39126L,39127L,
9600039128L,39129L,39130L,39131L,39132L,39133L,39134L,39135L,39136L,39137L,
9600139138L,39139L,39140L,39141L,39142L,39143L,39144L,39145L,39146L,39147L,
9600239148L,39149L,39150L,39151L,39152L,39153L,39154L,39155L,39156L,39157L,
9600339158L,39159L,39160L,39161L,39162L,39163L,39164L,39165L,39166L,39167L,
9600439168L,39169L,39170L,39171L,39172L,39173L,39174L,39175L,39176L,39177L,
9600539178L,39179L,39180L,39181L,39182L,39183L,39184L,39185L,39186L,39187L,
9600639188L,39189L,39190L,39191L,39192L,39193L,39194L,39195L,39196L,39197L,
9600739198L,39199L,39200L,39201L,39202L,39203L,39204L,39205L,39206L,39207L,
9600839208L,39209L,39210L,39211L,39212L,39213L,39214L,39215L,39216L,39217L,
9600939218L,39219L,39220L,39221L,39222L,39223L,39224L,39225L,39226L,39227L,
9601039228L,39229L,39230L,39231L,39232L,39233L,39234L,39235L,39236L,39237L,
9601139238L,39239L,39240L,39241L,39242L,39243L,39244L,39245L,39246L,39247L,
9601239248L,39249L,39250L,39251L,39252L,39253L,39254L,39255L,39256L,39257L,
9601339258L,39259L,39260L,39261L,39262L,39263L,39264L,39265L,39266L,39267L,
9601439268L,39269L,39270L,39271L,39272L,39273L,39274L,39275L,39276L,39277L,
9601539278L,39279L,39280L,39281L,39282L,39283L,39284L,39285L,39286L,39287L,
9601639288L,39289L,39290L,39291L,39292L,39293L,39294L,39295L,39296L,39297L,
9601739298L,39299L,39300L,39301L,39302L,39303L,39304L,39305L,39306L,39307L,
9601839308L,39309L,39310L,39311L,39312L,39313L,39314L,39315L,39316L,39317L,
9601939318L,39319L,39320L,39321L,39322L,39323L,39324L,39325L,39326L,39327L,
9602039328L,39329L,39330L,39331L,39332L,39333L,39334L,39335L,39336L,39337L,
9602139338L,39339L,39340L,39341L,39342L,39343L,39344L,39345L,39346L,39347L,
9602239348L,39349L,39350L,39351L,39352L,39353L,39354L,39355L,39356L,39357L,
9602339358L,39359L,39360L,39361L,39362L,39363L,39364L,39365L,39366L,39367L,
9602439368L,39369L,39370L,39371L,39372L,39373L,39374L,39375L,39376L,39377L,
9602539378L,39379L,39380L,39381L,39382L,39383L,39384L,39385L,39386L,39387L,
9602639388L,39389L,39390L,39391L,39392L,39393L,39394L,39395L,39396L,39397L,
9602739398L,39399L,39400L,39401L,39402L,39403L,39404L,39405L,39406L,39407L,
9602839408L,39409L,39410L,39411L,39412L,39413L,39414L,39415L,39416L,39417L,
9602939418L,39419L,39420L,39421L,39422L,39423L,39424L,39425L,39426L,39427L,
9603039428L,39429L,39430L,39431L,39432L,39433L,39434L,39435L,39436L,39437L,
9603139438L,39439L,39440L,39441L,39442L,39443L,39444L,39445L,39446L,39447L,
9603239448L,39449L,39450L,39451L,39452L,39453L,39454L,39455L,39456L,39457L,
9603339458L,39459L,39460L,39461L,39462L,39463L,39464L,39465L,39466L,39467L,
9603439468L,39469L,39470L,39471L,39472L,39473L,39474L,39475L,39476L,39477L,
9603539478L,39479L,39480L,39481L,39482L,39483L,39484L,39485L,39486L,39487L,
9603639488L,39489L,39490L,39491L,39492L,39493L,39494L,39495L,39496L,39497L,
9603739498L,39499L,39500L,39501L,39502L,39503L,39504L,39505L,39506L,39507L,
9603839508L,39509L,39510L,39511L,39512L,39513L,39514L,39515L,39516L,39517L,
9603939518L,39519L,39520L,39521L,39522L,39523L,39524L,39525L,39526L,39527L,
9604039528L,39529L,39530L,39531L,39532L,39533L,39534L,39535L,39536L,39537L,
9604139538L,39539L,39540L,39541L,39542L,39543L,39544L,39545L,39546L,39547L,
9604239548L,39549L,39550L,39551L,39552L,39553L,39554L,39555L,39556L,39557L,
9604339558L,39559L,39560L,39561L,39562L,39563L,39564L,39565L,39566L,39567L,
9604439568L,39569L,39570L,39571L,39572L,39573L,39574L,39575L,39576L,39577L,
9604539578L,39579L,39580L,39581L,39582L,39583L,39584L,39585L,39586L,39587L,
9604639588L,39589L,39590L,39591L,39592L,39593L,39594L,39595L,39596L,39597L,
9604739598L,39599L,39600L,39601L,39602L,39603L,39604L,39605L,39606L,39607L,
9604839608L,39609L,39610L,39611L,39612L,39613L,39614L,39615L,39616L,39617L,
9604939618L,39619L,39620L,39621L,39622L,39623L,39624L,39625L,39626L,39627L,
9605039628L,39629L,39630L,39631L,39632L,39633L,39634L,39635L,39636L,39637L,
9605139638L,39639L,39640L,39641L,39642L,39643L,39644L,39645L,39646L,39647L,
9605239648L,39649L,39650L,39651L,39652L,39653L,39654L,39655L,39656L,39657L,
9605339658L,39659L,39660L,39661L,39662L,39663L,39664L,39665L,39666L,39667L,
9605439668L,39669L,39670L,39671L,39672L,39673L,39674L,39675L,39676L,39677L,
9605539678L,39679L,39680L,39681L,39682L,39683L,39684L,39685L,39686L,39687L,
9605639688L,39689L,39690L,39691L,39692L,39693L,39694L,39695L,39696L,39697L,
9605739698L,39699L,39700L,39701L,39702L,39703L,39704L,39705L,39706L,39707L,
9605839708L,39709L,39710L,39711L,39712L,39713L,39714L,39715L,39716L,39717L,
9605939718L,39719L,39720L,39721L,39722L,39723L,39724L,39725L,39726L,39727L,
9606039728L,39729L,39730L,39731L,39732L,39733L,39734L,39735L,39736L,39737L,
9606139738L,39739L,39740L,39741L,39742L,39743L,39744L,39745L,39746L,39747L,
9606239748L,39749L,39750L,39751L,39752L,39753L,39754L,39755L,39756L,39757L,
9606339758L,39759L,39760L,39761L,39762L,39763L,39764L,39765L,39766L,39767L,
9606439768L,39769L,39770L,39771L,39772L,39773L,39774L,39775L,39776L,39777L,
9606539778L,39779L,39780L,39781L,39782L,39783L,39784L,39785L,39786L,39787L,
9606639788L,39789L,39790L,39791L,39792L,39793L,39794L,39795L,39796L,39797L,
9606739798L,39799L,39800L,39801L,39802L,39803L,39804L,39805L,39806L,39807L,
9606839808L,39809L,39810L,39811L,39812L,39813L,39814L,39815L,39816L,39817L,
9606939818L,39819L,39820L,39821L,39822L,39823L,39824L,39825L,39826L,39827L,
9607039828L,39829L,39830L,39831L,39832L,39833L,39834L,39835L,39836L,39837L,
9607139838L,39839L,39840L,39841L,39842L,39843L,39844L,39845L,39846L,39847L,
9607239848L,39849L,39850L,39851L,39852L,39853L,39854L,39855L,39856L,39857L,
9607339858L,39859L,39860L,39861L,39862L,39863L,39864L,39865L,39866L,39867L,
9607439868L,39869L,39870L,39871L,39872L,39873L,39874L,39875L,39876L,39877L,
9607539878L,39879L,39880L,39881L,39882L,39883L,39884L,39885L,39886L,39887L,
9607639888L,39889L,39890L,39891L,39892L,39893L,39894L,39895L,39896L,39897L,
9607739898L,39899L,39900L,39901L,39902L,39903L,39904L,39905L,39906L,39907L,
9607839908L,39909L,39910L,39911L,39912L,39913L,39914L,39915L,39916L,39917L,
9607939918L,39919L,39920L,39921L,39922L,39923L,39924L,39925L,39926L,39927L,
9608039928L,39929L,39930L,39931L,39932L,39933L,39934L,39935L,39936L,39937L,
9608139938L,39939L,39940L,39941L,39942L,39943L,39944L,39945L,39946L,39947L,
9608239948L,39949L,39950L,39951L,39952L,39953L,39954L,39955L,39956L,39957L,
9608339958L,39959L,39960L,39961L,39962L,39963L,39964L,39965L,39966L,39967L,
9608439968L,39969L,39970L,39971L,39972L,39973L,39974L,39975L,39976L,39977L,
9608539978L,39979L,39980L,39981L,39982L,39983L,39984L,39985L,39986L,39987L,
9608639988L,39989L,39990L,39991L,39992L,39993L,39994L,39995L,39996L,39997L,
9608739998L,39999L,40000L,40001L,40002L,40003L,40004L,40005L,40006L,40007L,
9608840008L,40009L,40010L,40011L,40012L,40013L,40014L,40015L,40016L,40017L,
9608940018L,40019L,40020L,40021L,40022L,40023L,40024L,40025L,40026L,40027L,
9609040028L,40029L,40030L,40031L,40032L,40033L,40034L,40035L,40036L,40037L,
9609140038L,40039L,40040L,40041L,40042L,40043L,40044L,40045L,40046L,40047L,
9609240048L,40049L,40050L,40051L,40052L,40053L,40054L,40055L,40056L,40057L,
9609340058L,40059L,40060L,40061L,40062L,40063L,40064L,40065L,40066L,40067L,
9609440068L,40069L,40070L,40071L,40072L,40073L,40074L,40075L,40076L,40077L,
9609540078L,40079L,40080L,40081L,40082L,40083L,40084L,40085L,40086L,40087L,
9609640088L,40089L,40090L,40091L,40092L,40093L,40094L,40095L,40096L,40097L,
9609740098L,40099L,40100L,40101L,40102L,40103L,40104L,40105L,40106L,40107L,
9609840108L,40109L,40110L,40111L,40112L,40113L,40114L,40115L,40116L,40117L,
9609940118L,40119L,40120L,40121L,40122L,40123L,40124L,40125L,40126L,40127L,
9610040128L,40129L,40130L,40131L,40132L,40133L,40134L,40135L,40136L,40137L,
9610140138L,40139L,40140L,40141L,40142L,40143L,40144L,40145L,40146L,40147L,
9610240148L,40149L,40150L,40151L,40152L,40153L,40154L,40155L,40156L,40157L,
9610340158L,40159L,40160L,40161L,40162L,40163L,40164L,40165L,40166L,40167L,
9610440168L,40169L,40170L,40171L,40172L,40173L,40174L,40175L,40176L,40177L,
9610540178L,40179L,40180L,40181L,40182L,40183L,40184L,40185L,40186L,40187L,
9610640188L,40189L,40190L,40191L,40192L,40193L,40194L,40195L,40196L,40197L,
9610740198L,40199L,40200L,40201L,40202L,40203L,40204L,40205L,40206L,40207L,
9610840208L,40209L,40210L,40211L,40212L,40213L,40214L,40215L,40216L,40217L,
9610940218L,40219L,40220L,40221L,40222L,40223L,40224L,40225L,40226L,40227L,
9611040228L,40229L,40230L,40231L,40232L,40233L,40234L,40235L,40236L,40237L,
9611140238L,40239L,40240L,40241L,40242L,40243L,40244L,40245L,40246L,40247L,
9611240248L,40249L,40250L,40251L,40252L,40253L,40254L,40255L,40256L,40257L,
9611340258L,40259L,40260L,40261L,40262L,40263L,40264L,40265L,40266L,40267L,
9611440268L,40269L,40270L,40271L,40272L,40273L,40274L,40275L,40276L,40277L,
9611540278L,40279L,40280L,40281L,40282L,40283L,40284L,40285L,40286L,40287L,
9611640288L,40289L,40290L,40291L,40292L,40293L,40294L,40295L,40296L,40297L,
9611740298L,40299L,40300L,40301L,40302L,40303L,40304L,40305L,40306L,40307L,
9611840308L,40309L,40310L,40311L,40312L,40313L,40314L,40315L,40316L,40317L,
9611940318L,40319L,40320L,40321L,40322L,40323L,40324L,40325L,40326L,40327L,
9612040328L,40329L,40330L,40331L,40332L,40333L,40334L,40335L,40336L,40337L,
9612140338L,40339L,40340L,40341L,40342L,40343L,40344L,40345L,40346L,40347L,
9612240348L,40349L,40350L,40351L,40352L,40353L,40354L,40355L,40356L,40357L,
9612340358L,40359L,40360L,40361L,40362L,40363L,40364L,40365L,40366L,40367L,
9612440368L,40369L,40370L,40371L,40372L,40373L,40374L,40375L,40376L,40377L,
9612540378L,40379L,40380L,40381L,40382L,40383L,40384L,40385L,40386L,40387L,
9612640388L,40389L,40390L,40391L,40392L,40393L,40394L,40395L,40396L,40397L,
9612740398L,40399L,40400L,40401L,40402L,40403L,40404L,40405L,40406L,40407L,
9612840408L,40409L,40410L,40411L,40412L,40413L,40414L,40415L,40416L,40417L,
9612940418L,40419L,40420L,40421L,40422L,40423L,40424L,40425L,40426L,40427L,
9613040428L,40429L,40430L,40431L,40432L,40433L,40434L,40435L,40436L,40437L,
9613140438L,40439L,40440L,40441L,40442L,40443L,40444L,40445L,40446L,40447L,
9613240448L,40449L,40450L,40451L,40452L,40453L,40454L,40455L,40456L,40457L,
9613340458L,40459L,40460L,40461L,40462L,40463L,40464L,40465L,40466L,40467L,
9613440468L,40469L,40470L,40471L,40472L,40473L,40474L,40475L,40476L,40477L,
9613540478L,40479L,40480L,40481L,40482L,40483L,40484L,40485L,40486L,40487L,
9613640488L,40489L,40490L,40491L,40492L,40493L,40494L,40495L,40496L,40497L,
9613740498L,40499L,40500L,40501L,40502L,40503L,40504L,40505L,40506L,40507L,
9613840508L,40509L,40510L,40511L,40512L,40513L,40514L,40515L,40516L,40517L,
9613940518L,40519L,40520L,40521L,40522L,40523L,40524L,40525L,40526L,40527L,
9614040528L,40529L,40530L,40531L,40532L,40533L,40534L,40535L,40536L,40537L,
9614140538L,40539L,40540L,40541L,40542L,40543L,40544L,40545L,40546L,40547L,
9614240548L,40549L,40550L,40551L,40552L,40553L,40554L,40555L,40556L,40557L,
9614340558L,40559L,40560L,40561L,40562L,40563L,40564L,40565L,40566L,40567L,
9614440568L,40569L,40570L,40571L,40572L,40573L,40574L,40575L,40576L,40577L,
9614540578L,40579L,40580L,40581L,40582L,40583L,40584L,40585L,40586L,40587L,
9614640588L,40589L,40590L,40591L,40592L,40593L,40594L,40595L,40596L,40597L,
9614740598L,40599L,40600L,40601L,40602L,40603L,40604L,40605L,40606L,40607L,
9614840608L,40609L,40610L,40611L,40612L,40613L,40614L,40615L,40616L,40617L,
9614940618L,40619L,40620L,40621L,40622L,40623L,40624L,40625L,40626L,40627L,
9615040628L,40629L,40630L,40631L,40632L,40633L,40634L,40635L,40636L,40637L,
9615140638L,40639L,40640L,40641L,40642L,40643L,40644L,40645L,40646L,40647L,
9615240648L,40649L,40650L,40651L,40652L,40653L,40654L,40655L,40656L,40657L,
9615340658L,40659L,40660L,40661L,40662L,40663L,40664L,40665L,40666L,40667L,
9615440668L,40669L,40670L,40671L,40672L,40673L,40674L,40675L,40676L,40677L,
9615540678L,40679L,40680L,40681L,40682L,40683L,40684L,40685L,40686L,40687L,
9615640688L,40689L,40690L,40691L,40692L,40693L,40694L,40695L,40696L,40697L,
9615740698L,40699L,40700L,40701L,40702L,40703L,40704L,40705L,40706L,40707L,
9615840708L,40709L,40710L,40711L,40712L,40713L,40714L,40715L,40716L,40717L,
9615940718L,40719L,40720L,40721L,40722L,40723L,40724L,40725L,40726L,40727L,
9616040728L,40729L,40730L,40731L,40732L,40733L,40734L,40735L,40736L,40737L,
9616140738L,40739L,40740L,40741L,40742L,40743L,40744L,40745L,40746L,40747L,
9616240748L,40749L,40750L,40751L,40752L,40753L,40754L,40755L,40756L,40757L,
9616340758L,40759L,40760L,40761L,40762L,40763L,40764L,40765L,40766L,40767L,
9616440768L,40769L,40770L,40771L,40772L,40773L,40774L,40775L,40776L,40777L,
9616540778L,40779L,40780L,40781L,40782L,40783L,40784L,40785L,40786L,40787L,
9616640788L,40789L,40790L,40791L,40792L,40793L,40794L,40795L,40796L,40797L,
9616740798L,40799L,40800L,40801L,40802L,40803L,40804L,40805L,40806L,40807L,
9616840808L,40809L,40810L,40811L,40812L,40813L,40814L,40815L,40816L,40817L,
9616940818L,40819L,40820L,40821L,40822L,40823L,40824L,40825L,40826L,40827L,
9617040828L,40829L,40830L,40831L,40832L,40833L,40834L,40835L,40836L,40837L,
9617140838L,40839L,40840L,40841L,40842L,40843L,40844L,40845L,40846L,40847L,
9617240848L,40849L,40850L,40851L,40852L,40853L,40854L,40855L,40856L,40857L,
9617340858L,40859L,40860L,40861L,40862L,40863L,40864L,40865L,40866L,40867L,
9617440868L,40869L,40870L,40871L,40872L,40873L,40874L,40875L,40876L,40877L,
9617540878L,40879L,40880L,40881L,40882L,40883L,40884L,40885L,40886L,40887L,
9617640888L,40889L,40890L,40891L,40892L,40893L,40894L,40895L,40896L,40897L,
9617740898L,40899L,40900L,40901L,40902L,40903L,40904L,40905L,40906L,40907L,
9617840908L,40909L,40910L,40911L,40912L,40913L,40914L,40915L,40916L,40917L,
9617940918L,40919L,40920L,40921L,40922L,40923L,40924L,40925L,40926L,40927L,
9618040928L,40929L,40930L,40931L,40932L,40933L,40934L,40935L,40936L,40937L,
9618140938L,40939L,40940L,40941L,40942L,40943L,40944L,40945L,40946L,40947L,
9618240948L,40949L,40950L,40951L,40952L,40953L,40954L,40955L,40956L,40957L,
9618340958L,40959L,40960L,40961L,40962L,40963L,40964L,40965L,40966L,40967L,
9618440968L,40969L,40970L,40971L,40972L,40973L,40974L,40975L,40976L,40977L,
9618540978L,40979L,40980L,40981L,40982L,40983L,40984L,40985L,40986L,40987L,
9618640988L,40989L,40990L,40991L,40992L,40993L,40994L,40995L,40996L,40997L,
9618740998L,40999L,41000L,41001L,41002L,41003L,41004L,41005L,41006L,41007L,
9618841008L,41009L,41010L,41011L,41012L,41013L,41014L,41015L,41016L,41017L,
9618941018L,41019L,41020L,41021L,41022L,41023L,41024L,41025L,41026L,41027L,
9619041028L,41029L,41030L,41031L,41032L,41033L,41034L,41035L,41036L,41037L,
9619141038L,41039L,41040L,41041L,41042L,41043L,41044L,41045L,41046L,41047L,
9619241048L,41049L,41050L,41051L,41052L,41053L,41054L,41055L,41056L,41057L,
9619341058L,41059L,41060L,41061L,41062L,41063L,41064L,41065L,41066L,41067L,
9619441068L,41069L,41070L,41071L,41072L,41073L,41074L,41075L,41076L,41077L,
9619541078L,41079L,41080L,41081L,41082L,41083L,41084L,41085L,41086L,41087L,
9619641088L,41089L,41090L,41091L,41092L,41093L,41094L,41095L,41096L,41097L,
9619741098L,41099L,41100L,41101L,41102L,41103L,41104L,41105L,41106L,41107L,
9619841108L,41109L,41110L,41111L,41112L,41113L,41114L,41115L,41116L,41117L,
9619941118L,41119L,41120L,41121L,41122L,41123L,41124L,41125L,41126L,41127L,
9620041128L,41129L,41130L,41131L,41132L,41133L,41134L,41135L,41136L,41137L,
9620141138L,41139L,41140L,41141L,41142L,41143L,41144L,41145L,41146L,41147L,
9620241148L,41149L,41150L,41151L,41152L,41153L,41154L,41155L,41156L,41157L,
9620341158L,41159L,41160L,41161L,41162L,41163L,41164L,41165L,41166L,41167L,
9620441168L,41169L,41170L,41171L,41172L,41173L,41174L,41175L,41176L,41177L,
9620541178L,41179L,41180L,41181L,41182L,41183L,41184L,41185L,41186L,41187L,
9620641188L,41189L,41190L,41191L,41192L,41193L,41194L,41195L,41196L,41197L,
9620741198L,41199L,41200L,41201L,41202L,41203L,41204L,41205L,41206L,41207L,
9620841208L,41209L,41210L,41211L,41212L,41213L,41214L,41215L,41216L,41217L,
9620941218L,41219L,41220L,41221L,41222L,41223L,41224L,41225L,41226L,41227L,
9621041228L,41229L,41230L,41231L,41232L,41233L,41234L,41235L,41236L,41237L,
9621141238L,41239L,41240L,41241L,41242L,41243L,41244L,41245L,41246L,41247L,
9621241248L,41249L,41250L,41251L,41252L,41253L,41254L,41255L,41256L,41257L,
9621341258L,41259L,41260L,41261L,41262L,41263L,41264L,41265L,41266L,41267L,
9621441268L,41269L,41270L,41271L,41272L,41273L,41274L,41275L,41276L,41277L,
9621541278L,41279L,41280L,41281L,41282L,41283L,41284L,41285L,41286L,41287L,
9621641288L,41289L,41290L,41291L,41292L,41293L,41294L,41295L,41296L,41297L,
9621741298L,41299L,41300L,41301L,41302L,41303L,41304L,41305L,41306L,41307L,
9621841308L,41309L,41310L,41311L,41312L,41313L,41314L,41315L,41316L,41317L,
9621941318L,41319L,41320L,41321L,41322L,41323L,41324L,41325L,41326L,41327L,
9622041328L,41329L,41330L,41331L,41332L,41333L,41334L,41335L,41336L,41337L,
9622141338L,41339L,41340L,41341L,41342L,41343L,41344L,41345L,41346L,41347L,
9622241348L,41349L,41350L,41351L,41352L,41353L,41354L,41355L,41356L,41357L,
9622341358L,41359L,41360L,41361L,41362L,41363L,41364L,41365L,41366L,41367L,
9622441368L,41369L,41370L,41371L,41372L,41373L,41374L,41375L,41376L,41377L,
9622541378L,41379L,41380L,41381L,41382L,41383L,41384L,41385L,41386L,41387L,
9622641388L,41389L,41390L,41391L,41392L,41393L,41394L,41395L,41396L,41397L,
9622741398L,41399L,41400L,41401L,41402L,41403L,41404L,41405L,41406L,41407L,
9622841408L,41409L,41410L,41411L,41412L,41413L,41414L,41415L,41416L,41417L,
9622941418L,41419L,41420L,41421L,41422L,41423L,41424L,41425L,41426L,41427L,
9623041428L,41429L,41430L,41431L,41432L,41433L,41434L,41435L,41436L,41437L,
9623141438L,41439L,41440L,41441L,41442L,41443L,41444L,41445L,41446L,41447L,
9623241448L,41449L,41450L,41451L,41452L,41453L,41454L,41455L,41456L,41457L,
9623341458L,41459L,41460L,41461L,41462L,41463L,41464L,41465L,41466L,41467L,
9623441468L,41469L,41470L,41471L,41472L,41473L,41474L,41475L,41476L,41477L,
9623541478L,41479L,41480L,41481L,41482L,41483L,41484L,41485L,41486L,41487L,
9623641488L,41489L,41490L,41491L,41492L,41493L,41494L,41495L,41496L,41497L,
9623741498L,41499L,41500L,41501L,41502L,41503L,41504L,41505L,41506L,41507L,
9623841508L,41509L,41510L,41511L,41512L,41513L,41514L,41515L,41516L,41517L,
9623941518L,41519L,41520L,41521L,41522L,41523L,41524L,41525L,41526L,41527L,
9624041528L,41529L,41530L,41531L,41532L,41533L,41534L,41535L,41536L,41537L,
9624141538L,41539L,41540L,41541L,41542L,41543L,41544L,41545L,41546L,41547L,
9624241548L,41549L,41550L,41551L,41552L,41553L,41554L,41555L,41556L,41557L,
9624341558L,41559L,41560L,41561L,41562L,41563L,41564L,41565L,41566L,41567L,
9624441568L,41569L,41570L,41571L,41572L,41573L,41574L,41575L,41576L,41577L,
9624541578L,41579L,41580L,41581L,41582L,41583L,41584L,41585L,41586L,41587L,
9624641588L,41589L,41590L,41591L,41592L,41593L,41594L,41595L,41596L,41597L,
9624741598L,41599L,41600L,41601L,41602L,41603L,41604L,41605L,41606L,41607L,
9624841608L,41609L,41610L,41611L,41612L,41613L,41614L,41615L,41616L,41617L,
9624941618L,41619L,41620L,41621L,41622L,41623L,41624L,41625L,41626L,41627L,
9625041628L,41629L,41630L,41631L,41632L,41633L,41634L,41635L,41636L,41637L,
9625141638L,41639L,41640L,41641L,41642L,41643L,41644L,41645L,41646L,41647L,
9625241648L,41649L,41650L,41651L,41652L,41653L,41654L,41655L,41656L,41657L,
9625341658L,41659L,41660L,41661L,41662L,41663L,41664L,41665L,41666L,41667L,
9625441668L,41669L,41670L,41671L,41672L,41673L,41674L,41675L,41676L,41677L,
9625541678L,41679L,41680L,41681L,41682L,41683L,41684L,41685L,41686L,41687L,
9625641688L,41689L,41690L,41691L,41692L,41693L,41694L,41695L,41696L,41697L,
9625741698L,41699L,41700L,41701L,41702L,41703L,41704L,41705L,41706L,41707L,
9625841708L,41709L,41710L,41711L,41712L,41713L,41714L,41715L,41716L,41717L,
9625941718L,41719L,41720L,41721L,41722L,41723L,41724L,41725L,41726L,41727L,
9626041728L,41729L,41730L,41731L,41732L,41733L,41734L,41735L,41736L,41737L,
9626141738L,41739L,41740L,41741L,41742L,41743L,41744L,41745L,41746L,41747L,
9626241748L,41749L,41750L,41751L,41752L,41753L,41754L,41755L,41756L,41757L,
9626341758L,41759L,41760L,41761L,41762L,41763L,41764L,41765L,41766L,41767L,
9626441768L,41769L,41770L,41771L,41772L,41773L,41774L,41775L,41776L,41777L,
9626541778L,41779L,41780L,41781L,41782L,41783L,41784L,41785L,41786L,41787L,
9626641788L,41789L,41790L,41791L,41792L,41793L,41794L,41795L,41796L,41797L,
9626741798L,41799L,41800L,41801L,41802L,41803L,41804L,41805L,41806L,41807L,
9626841808L,41809L,41810L,41811L,41812L,41813L,41814L,41815L,41816L,41817L,
9626941818L,41819L,41820L,41821L,41822L,41823L,41824L,41825L,41826L,41827L,
9627041828L,41829L,41830L,41831L,41832L,41833L,41834L,41835L,41836L,41837L,
9627141838L,41839L,41840L,41841L,41842L,41843L,41844L,41845L,41846L,41847L,
9627241848L,41849L,41850L,41851L,41852L,41853L,41854L,41855L,41856L,41857L,
9627341858L,41859L,41860L,41861L,41862L,41863L,41864L,41865L,41866L,41867L,
9627441868L,41869L,41870L,41871L,41872L,41873L,41874L,41875L,41876L,41877L,
9627541878L,41879L,41880L,41881L,41882L,41883L,41884L,41885L,41886L,41887L,
9627641888L,41889L,41890L,41891L,41892L,41893L,41894L,41895L,41896L,41897L,
9627741898L,41899L,41900L,41901L,41902L,41903L,41904L,41905L,41906L,41907L,
9627841908L,41909L,41910L,41911L,41912L,41913L,41914L,41915L,41916L,41917L,
9627941918L,41919L,41920L,41921L,41922L,41923L,41924L,41925L,41926L,41927L,
9628041928L,41929L,41930L,41931L,41932L,41933L,41934L,41935L,41936L,41937L,
9628141938L,41939L,41940L,41941L,41942L,41943L,41944L,41945L,41946L,41947L,
9628241948L,41949L,41950L,41951L,41952L,41953L,41954L,41955L,41956L,41957L,
9628341958L,41959L,41960L,41961L,41962L,41963L,41964L,41965L,41966L,41967L,
9628441968L,41969L,41970L,41971L,41972L,41973L,41974L,41975L,41976L,41977L,
9628541978L,41979L,41980L,41981L,41982L,41983L,41984L,41985L,41986L,41987L,
9628641988L,41989L,41990L,41991L,41992L,41993L,41994L,41995L,41996L,41997L,
9628741998L,41999L,42000L,42001L,42002L,42003L,42004L,42005L,42006L,42007L,
9628842008L,42009L,42010L,42011L,42012L,42013L,42014L,42015L,42016L,42017L,
9628942018L,42019L,42020L,42021L,42022L,42023L,42024L,42025L,42026L,42027L,
9629042028L,42029L,42030L,42031L,42032L,42033L,42034L,42035L,42036L,42037L,
9629142038L,42039L,42040L,42041L,42042L,42043L,42044L,42045L,42046L,42047L,
9629242048L,42049L,42050L,42051L,42052L,42053L,42054L,42055L,42056L,42057L,
9629342058L,42059L,42060L,42061L,42062L,42063L,42064L,42065L,42066L,42067L,
9629442068L,42069L,42070L,42071L,42072L,42073L,42074L,42075L,42076L,42077L,
9629542078L,42079L,42080L,42081L,42082L,42083L,42084L,42085L,42086L,42087L,
9629642088L,42089L,42090L,42091L,42092L,42093L,42094L,42095L,42096L,42097L,
9629742098L,42099L,42100L,42101L,42102L,42103L,42104L,42105L,42106L,42107L,
9629842108L,42109L,42110L,42111L,42112L,42113L,42114L,42115L,42116L,42117L,
9629942118L,42119L,42120L,42121L,42122L,42123L,42124L,42125L,42126L,42127L,
9630042128L,42129L,42130L,42131L,42132L,42133L,42134L,42135L,42136L,42137L,
9630142138L,42139L,42140L,42141L,42142L,42143L,42144L,42145L,42146L,42147L,
9630242148L,42149L,42150L,42151L,42152L,42153L,42154L,42155L,42156L,42157L,
9630342158L,42159L,42160L,42161L,42162L,42163L,42164L,42165L,42166L,42167L,
9630442168L,42169L,42170L,42171L,42172L,42173L,42174L,42175L,42176L,42177L,
9630542178L,42179L,42180L,42181L,42182L,42183L,42184L,42185L,42186L,42187L,
9630642188L,42189L,42190L,42191L,42192L,42193L,42194L,42195L,42196L,42197L,
9630742198L,42199L,42200L,42201L,42202L,42203L,42204L,42205L,42206L,42207L,
9630842208L,42209L,42210L,42211L,42212L,42213L,42214L,42215L,42216L,42217L,
9630942218L,42219L,42220L,42221L,42222L,42223L,42224L,42225L,42226L,42227L,
9631042228L,42229L,42230L,42231L,42232L,42233L,42234L,42235L,42236L,42237L,
9631142238L,42239L,42240L,42241L,42242L,42243L,42244L,42245L,42246L,42247L,
9631242248L,42249L,42250L,42251L,42252L,42253L,42254L,42255L,42256L,42257L,
9631342258L,42259L,42260L,42261L,42262L,42263L,42264L,42265L,42266L,42267L,
9631442268L,42269L,42270L,42271L,42272L,42273L,42274L,42275L,42276L,42277L,
9631542278L,42279L,42280L,42281L,42282L,42283L,42284L,42285L,42286L,42287L,
9631642288L,42289L,42290L,42291L,42292L,42293L,42294L,42295L,42296L,42297L,
9631742298L,42299L,42300L,42301L,42302L,42303L,42304L,42305L,42306L,42307L,
9631842308L,42309L,42310L,42311L,42312L,42313L,42314L,42315L,42316L,42317L,
9631942318L,42319L,42320L,42321L,42322L,42323L,42324L,42325L,42326L,42327L,
9632042328L,42329L,42330L,42331L,42332L,42333L,42334L,42335L,42336L,42337L,
9632142338L,42339L,42340L,42341L,42342L,42343L,42344L,42345L,42346L,42347L,
9632242348L,42349L,42350L,42351L,42352L,42353L,42354L,42355L,42356L,42357L,
9632342358L,42359L,42360L,42361L,42362L,42363L,42364L,42365L,42366L,42367L,
9632442368L,42369L,42370L,42371L,42372L,42373L,42374L,42375L,42376L,42377L,
9632542378L,42379L,42380L,42381L,42382L,42383L,42384L,42385L,42386L,42387L,
9632642388L,42389L,42390L,42391L,42392L,42393L,42394L,42395L,42396L,42397L,
9632742398L,42399L,42400L,42401L,42402L,42403L,42404L,42405L,42406L,42407L,
9632842408L,42409L,42410L,42411L,42412L,42413L,42414L,42415L,42416L,42417L,
9632942418L,42419L,42420L,42421L,42422L,42423L,42424L,42425L,42426L,42427L,
9633042428L,42429L,42430L,42431L,42432L,42433L,42434L,42435L,42436L,42437L,
9633142438L,42439L,42440L,42441L,42442L,42443L,42444L,42445L,42446L,42447L,
9633242448L,42449L,42450L,42451L,42452L,42453L,42454L,42455L,42456L,42457L,
9633342458L,42459L,42460L,42461L,42462L,42463L,42464L,42465L,42466L,42467L,
9633442468L,42469L,42470L,42471L,42472L,42473L,42474L,42475L,42476L,42477L,
9633542478L,42479L,42480L,42481L,42482L,42483L,42484L,42485L,42486L,42487L,
9633642488L,42489L,42490L,42491L,42492L,42493L,42494L,42495L,42496L,42497L,
9633742498L,42499L,42500L,42501L,42502L,42503L,42504L,42505L,42506L,42507L,
9633842508L,42509L,42510L,42511L,42512L,42513L,42514L,42515L,42516L,42517L,
9633942518L,42519L,42520L,42521L,42522L,42523L,42524L,42525L,42526L,42527L,
9634042528L,42529L,42530L,42531L,42532L,42533L,42534L,42535L,42536L,42537L,
9634142538L,42539L,42540L,42541L,42542L,42543L,42544L,42545L,42546L,42547L,
9634242548L,42549L,42550L,42551L,42552L,42553L,42554L,42555L,42556L,42557L,
9634342558L,42559L,42560L,42560L,42562L,42562L,42564L,42564L,42566L,42566L,
9634442568L,42568L,42570L,42570L,42572L,42572L,42574L,42574L,42576L,42576L,
9634542578L,42578L,42580L,42580L,42582L,42582L,42584L,42584L,42586L,42586L,
9634642588L,42588L,42590L,42590L,42592L,42592L,42594L,42594L,42596L,42596L,
9634742598L,42598L,42600L,42600L,42602L,42602L,42604L,42604L,42606L,42607L,
9634842608L,42609L,42610L,42611L,42612L,42613L,42614L,42615L,42616L,42617L,
9634942618L,42619L,42620L,42621L,42622L,42623L,42624L,42624L,42626L,42626L,
9635042628L,42628L,42630L,42630L,42632L,42632L,42634L,42634L,42636L,42636L,
9635142638L,42638L,42640L,42640L,42642L,42642L,42644L,42644L,42646L,42646L,
9635242648L,42648L,42650L,42650L,42652L,42653L,42654L,42655L,42656L,42657L,
9635342658L,42659L,42660L,42661L,42662L,42663L,42664L,42665L,42666L,42667L,
9635442668L,42669L,42670L,42671L,42672L,42673L,42674L,42675L,42676L,42677L,
9635542678L,42679L,42680L,42681L,42682L,42683L,42684L,42685L,42686L,42687L,
9635642688L,42689L,42690L,42691L,42692L,42693L,42694L,42695L,42696L,42697L,
9635742698L,42699L,42700L,42701L,42702L,42703L,42704L,42705L,42706L,42707L,
9635842708L,42709L,42710L,42711L,42712L,42713L,42714L,42715L,42716L,42717L,
9635942718L,42719L,42720L,42721L,42722L,42723L,42724L,42725L,42726L,42727L,
9636042728L,42729L,42730L,42731L,42732L,42733L,42734L,42735L,42736L,42737L,
9636142738L,42739L,42740L,42741L,42742L,42743L,42744L,42745L,42746L,42747L,
9636242748L,42749L,42750L,42751L,42752L,42753L,42754L,42755L,42756L,42757L,
9636342758L,42759L,42760L,42761L,42762L,42763L,42764L,42765L,42766L,42767L,
9636442768L,42769L,42770L,42771L,42772L,42773L,42774L,42775L,42776L,42777L,
9636542778L,42779L,42780L,42781L,42782L,42783L,42784L,42785L,42786L,42786L,
9636642788L,42788L,42790L,42790L,42792L,42792L,42794L,42794L,42796L,42796L,
9636742798L,42798L,42800L,42801L,42802L,42802L,42804L,42804L,42806L,42806L,
9636842808L,42808L,42810L,42810L,42812L,42812L,42814L,42814L,42816L,42816L,
9636942818L,42818L,42820L,42820L,42822L,42822L,42824L,42824L,42826L,42826L,
9637042828L,42828L,42830L,42830L,42832L,42832L,42834L,42834L,42836L,42836L,
9637142838L,42838L,42840L,42840L,42842L,42842L,42844L,42844L,42846L,42846L,
9637242848L,42848L,42850L,42850L,42852L,42852L,42854L,42854L,42856L,42856L,
9637342858L,42858L,42860L,42860L,42862L,42862L,42864L,42865L,42866L,42867L,
9637442868L,42869L,42870L,42871L,42872L,42873L,42873L,42875L,42875L,42877L,
9637542878L,42878L,42880L,42880L,42882L,42882L,42884L,42884L,42886L,42886L,
9637642888L,42889L,42890L,42891L,42891L,42893L,42894L,42895L,42896L,42896L,
9637742898L,42898L,42948L,42901L,42902L,42902L,42904L,42904L,42906L,42906L,
9637842908L,42908L,42910L,42910L,42912L,42912L,42914L,42914L,42916L,42916L,
9637942918L,42918L,42920L,42920L,42922L,42923L,42924L,42925L,42926L,42927L,
9638042928L,42929L,42930L,42931L,42932L,42932L,42934L,42934L,42936L,42936L,
9638142938L,42938L,42940L,42940L,42942L,42942L,42944L,42945L,42946L,42946L,
9638242948L,42949L,42950L,42951L,42952L,42953L,42954L,42955L,42956L,42957L,
9638342958L,42959L,42960L,42961L,42962L,42963L,42964L,42965L,42966L,42967L,
9638442968L,42969L,42970L,42971L,42972L,42973L,42974L,42975L,42976L,42977L,
9638542978L,42979L,42980L,42981L,42982L,42983L,42984L,42985L,42986L,42987L,
9638642988L,42989L,42990L,42991L,42992L,42993L,42994L,42995L,42996L,42997L,
9638742998L,42999L,43000L,43001L,43002L,43003L,43004L,43005L,43006L,43007L,
9638843008L,43009L,43010L,43011L,43012L,43013L,43014L,43015L,43016L,43017L,
9638943018L,43019L,43020L,43021L,43022L,43023L,43024L,43025L,43026L,43027L,
9639043028L,43029L,43030L,43031L,43032L,43033L,43034L,43035L,43036L,43037L,
9639143038L,43039L,43040L,43041L,43042L,43043L,43044L,43045L,43046L,43047L,
9639243048L,43049L,43050L,43051L,43052L,43053L,43054L,43055L,43056L,43057L,
9639343058L,43059L,43060L,43061L,43062L,43063L,43064L,43065L,43066L,43067L,
9639443068L,43069L,43070L,43071L,43072L,43073L,43074L,43075L,43076L,43077L,
9639543078L,43079L,43080L,43081L,43082L,43083L,43084L,43085L,43086L,43087L,
9639643088L,43089L,43090L,43091L,43092L,43093L,43094L,43095L,43096L,43097L,
9639743098L,43099L,43100L,43101L,43102L,43103L,43104L,43105L,43106L,43107L,
9639843108L,43109L,43110L,43111L,43112L,43113L,43114L,43115L,43116L,43117L,
9639943118L,43119L,43120L,43121L,43122L,43123L,43124L,43125L,43126L,43127L,
9640043128L,43129L,43130L,43131L,43132L,43133L,43134L,43135L,43136L,43137L,
9640143138L,43139L,43140L,43141L,43142L,43143L,43144L,43145L,43146L,43147L,
9640243148L,43149L,43150L,43151L,43152L,43153L,43154L,43155L,43156L,43157L,
9640343158L,43159L,43160L,43161L,43162L,43163L,43164L,43165L,43166L,43167L,
9640443168L,43169L,43170L,43171L,43172L,43173L,43174L,43175L,43176L,43177L,
9640543178L,43179L,43180L,43181L,43182L,43183L,43184L,43185L,43186L,43187L,
9640643188L,43189L,43190L,43191L,43192L,43193L,43194L,43195L,43196L,43197L,
9640743198L,43199L,43200L,43201L,43202L,43203L,43204L,43205L,43206L,43207L,
9640843208L,43209L,43210L,43211L,43212L,43213L,43214L,43215L,43216L,43217L,
9640943218L,43219L,43220L,43221L,43222L,43223L,43224L,43225L,43226L,43227L,
9641043228L,43229L,43230L,43231L,43232L,43233L,43234L,43235L,43236L,43237L,
9641143238L,43239L,43240L,43241L,43242L,43243L,43244L,43245L,43246L,43247L,
9641243248L,43249L,43250L,43251L,43252L,43253L,43254L,43255L,43256L,43257L,
9641343258L,43259L,43260L,43261L,43262L,43263L,43264L,43265L,43266L,43267L,
9641443268L,43269L,43270L,43271L,43272L,43273L,43274L,43275L,43276L,43277L,
9641543278L,43279L,43280L,43281L,43282L,43283L,43284L,43285L,43286L,43287L,
9641643288L,43289L,43290L,43291L,43292L,43293L,43294L,43295L,43296L,43297L,
9641743298L,43299L,43300L,43301L,43302L,43303L,43304L,43305L,43306L,43307L,
9641843308L,43309L,43310L,43311L,43312L,43313L,43314L,43315L,43316L,43317L,
9641943318L,43319L,43320L,43321L,43322L,43323L,43324L,43325L,43326L,43327L,
9642043328L,43329L,43330L,43331L,43332L,43333L,43334L,43335L,43336L,43337L,
9642143338L,43339L,43340L,43341L,43342L,43343L,43344L,43345L,43346L,43347L,
9642243348L,43349L,43350L,43351L,43352L,43353L,43354L,43355L,43356L,43357L,
9642343358L,43359L,43360L,43361L,43362L,43363L,43364L,43365L,43366L,43367L,
9642443368L,43369L,43370L,43371L,43372L,43373L,43374L,43375L,43376L,43377L,
9642543378L,43379L,43380L,43381L,43382L,43383L,43384L,43385L,43386L,43387L,
9642643388L,43389L,43390L,43391L,43392L,43393L,43394L,43395L,43396L,43397L,
9642743398L,43399L,43400L,43401L,43402L,43403L,43404L,43405L,43406L,43407L,
9642843408L,43409L,43410L,43411L,43412L,43413L,43414L,43415L,43416L,43417L,
9642943418L,43419L,43420L,43421L,43422L,43423L,43424L,43425L,43426L,43427L,
9643043428L,43429L,43430L,43431L,43432L,43433L,43434L,43435L,43436L,43437L,
9643143438L,43439L,43440L,43441L,43442L,43443L,43444L,43445L,43446L,43447L,
9643243448L,43449L,43450L,43451L,43452L,43453L,43454L,43455L,43456L,43457L,
9643343458L,43459L,43460L,43461L,43462L,43463L,43464L,43465L,43466L,43467L,
9643443468L,43469L,43470L,43471L,43472L,43473L,43474L,43475L,43476L,43477L,
9643543478L,43479L,43480L,43481L,43482L,43483L,43484L,43485L,43486L,43487L,
9643643488L,43489L,43490L,43491L,43492L,43493L,43494L,43495L,43496L,43497L,
9643743498L,43499L,43500L,43501L,43502L,43503L,43504L,43505L,43506L,43507L,
9643843508L,43509L,43510L,43511L,43512L,43513L,43514L,43515L,43516L,43517L,
9643943518L,43519L,43520L,43521L,43522L,43523L,43524L,43525L,43526L,43527L,
9644043528L,43529L,43530L,43531L,43532L,43533L,43534L,43535L,43536L,43537L,
9644143538L,43539L,43540L,43541L,43542L,43543L,43544L,43545L,43546L,43547L,
9644243548L,43549L,43550L,43551L,43552L,43553L,43554L,43555L,43556L,43557L,
9644343558L,43559L,43560L,43561L,43562L,43563L,43564L,43565L,43566L,43567L,
9644443568L,43569L,43570L,43571L,43572L,43573L,43574L,43575L,43576L,43577L,
9644543578L,43579L,43580L,43581L,43582L,43583L,43584L,43585L,43586L,43587L,
9644643588L,43589L,43590L,43591L,43592L,43593L,43594L,43595L,43596L,43597L,
9644743598L,43599L,43600L,43601L,43602L,43603L,43604L,43605L,43606L,43607L,
9644843608L,43609L,43610L,43611L,43612L,43613L,43614L,43615L,43616L,43617L,
9644943618L,43619L,43620L,43621L,43622L,43623L,43624L,43625L,43626L,43627L,
9645043628L,43629L,43630L,43631L,43632L,43633L,43634L,43635L,43636L,43637L,
9645143638L,43639L,43640L,43641L,43642L,43643L,43644L,43645L,43646L,43647L,
9645243648L,43649L,43650L,43651L,43652L,43653L,43654L,43655L,43656L,43657L,
9645343658L,43659L,43660L,43661L,43662L,43663L,43664L,43665L,43666L,43667L,
9645443668L,43669L,43670L,43671L,43672L,43673L,43674L,43675L,43676L,43677L,
9645543678L,43679L,43680L,43681L,43682L,43683L,43684L,43685L,43686L,43687L,
9645643688L,43689L,43690L,43691L,43692L,43693L,43694L,43695L,43696L,43697L,
9645743698L,43699L,43700L,43701L,43702L,43703L,43704L,43705L,43706L,43707L,
9645843708L,43709L,43710L,43711L,43712L,43713L,43714L,43715L,43716L,43717L,
9645943718L,43719L,43720L,43721L,43722L,43723L,43724L,43725L,43726L,43727L,
9646043728L,43729L,43730L,43731L,43732L,43733L,43734L,43735L,43736L,43737L,
9646143738L,43739L,43740L,43741L,43742L,43743L,43744L,43745L,43746L,43747L,
9646243748L,43749L,43750L,43751L,43752L,43753L,43754L,43755L,43756L,43757L,
9646343758L,43759L,43760L,43761L,43762L,43763L,43764L,43765L,43766L,43767L,
9646443768L,43769L,43770L,43771L,43772L,43773L,43774L,43775L,43776L,43777L,
9646543778L,43779L,43780L,43781L,43782L,43783L,43784L,43785L,43786L,43787L,
9646643788L,43789L,43790L,43791L,43792L,43793L,43794L,43795L,43796L,43797L,
9646743798L,43799L,43800L,43801L,43802L,43803L,43804L,43805L,43806L,43807L,
9646843808L,43809L,43810L,43811L,43812L,43813L,43814L,43815L,43816L,43817L,
9646943818L,43819L,43820L,43821L,43822L,43823L,43824L,43825L,43826L,43827L,
9647043828L,43829L,43830L,43831L,43832L,43833L,43834L,43835L,43836L,43837L,
9647143838L,43839L,43840L,43841L,43842L,43843L,43844L,43845L,43846L,43847L,
9647243848L,43849L,43850L,43851L,43852L,43853L,43854L,43855L,43856L,43857L,
9647343858L,42931L,43860L,43861L,43862L,43863L,43864L,43865L,43866L,43867L,
9647443868L,43869L,43870L,43871L,43872L,43873L,43874L,43875L,43876L,43877L,
9647543878L,43879L,43880L,43881L,43882L,43883L,43884L,43885L,43886L,43887L,5024,
964765025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,
964775040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,
964785055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,
964795070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,
964805085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,
964815100,5101,5102,5103,43968L,43969L,43970L,43971L,43972L,43973L,43974L,
9648243975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,43983L,43984L,
9648343985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,43993L,43994L,
9648443995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,44003L,44004L,
9648544005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,44013L,44014L,
9648644015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,44023L,44024L,
9648744025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,44033L,44034L,
9648844035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,44043L,44044L,
9648944045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,44053L,44054L,
9649044055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,44063L,44064L,
9649144065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,44073L,44074L,
9649244075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,44083L,44084L,
9649344085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,44093L,44094L,
9649444095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,44103L,44104L,
9649544105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,44113L,44114L,
9649644115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,44123L,44124L,
9649744125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,44133L,44134L,
9649844135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,44143L,44144L,
9649944145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,44153L,44154L,
9650044155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,44163L,44164L,
9650144165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,44173L,44174L,
9650244175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,44183L,44184L,
9650344185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,44193L,44194L,
9650444195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,44203L,44204L,
9650544205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,44213L,44214L,
9650644215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,44223L,44224L,
9650744225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,44233L,44234L,
9650844235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,44243L,44244L,
9650944245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,44253L,44254L,
9651044255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,44263L,44264L,
9651144265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,44273L,44274L,
9651244275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,44283L,44284L,
9651344285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,44293L,44294L,
9651444295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,44303L,44304L,
9651544305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,44313L,44314L,
9651644315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,44323L,44324L,
9651744325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,44333L,44334L,
9651844335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,44343L,44344L,
9651944345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,44353L,44354L,
9652044355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,44363L,44364L,
9652144365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,44373L,44374L,
9652244375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,44383L,44384L,
9652344385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,44393L,44394L,
9652444395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,44403L,44404L,
9652544405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,44413L,44414L,
9652644415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,44423L,44424L,
9652744425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,44433L,44434L,
9652844435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,44443L,44444L,
9652944445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,44453L,44454L,
9653044455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,44463L,44464L,
9653144465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,44473L,44474L,
9653244475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,44483L,44484L,
9653344485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,44493L,44494L,
9653444495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,44503L,44504L,
9653544505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,44513L,44514L,
9653644515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,44523L,44524L,
9653744525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,44533L,44534L,
9653844535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,44543L,44544L,
9653944545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,44553L,44554L,
9654044555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,44563L,44564L,
9654144565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,44573L,44574L,
9654244575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,44583L,44584L,
9654344585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,44593L,44594L,
9654444595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,44603L,44604L,
9654544605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,44613L,44614L,
9654644615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,44623L,44624L,
9654744625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,44633L,44634L,
9654844635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,44643L,44644L,
9654944645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,44653L,44654L,
9655044655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,44663L,44664L,
9655144665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,44673L,44674L,
9655244675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,44683L,44684L,
9655344685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,44693L,44694L,
9655444695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,44703L,44704L,
9655544705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,44713L,44714L,
9655644715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,44723L,44724L,
9655744725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,44733L,44734L,
9655844735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,44743L,44744L,
9655944745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,44753L,44754L,
9656044755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,44763L,44764L,
9656144765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,44773L,44774L,
9656244775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,44783L,44784L,
9656344785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,44793L,44794L,
9656444795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,44803L,44804L,
9656544805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,44813L,44814L,
9656644815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,44823L,44824L,
9656744825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,44833L,44834L,
9656844835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,44843L,44844L,
9656944845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,44853L,44854L,
9657044855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,44863L,44864L,
9657144865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,44873L,44874L,
9657244875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,44883L,44884L,
9657344885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,44893L,44894L,
9657444895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,44903L,44904L,
9657544905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,44913L,44914L,
9657644915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,44923L,44924L,
9657744925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,44933L,44934L,
9657844935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,44943L,44944L,
9657944945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,44953L,44954L,
9658044955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,44963L,44964L,
9658144965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,44973L,44974L,
9658244975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,44983L,44984L,
9658344985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,44993L,44994L,
9658444995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,45003L,45004L,
9658545005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,45013L,45014L,
9658645015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,45023L,45024L,
9658745025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,45033L,45034L,
9658845035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,45043L,45044L,
9658945045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,45053L,45054L,
9659045055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,45063L,45064L,
9659145065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,45073L,45074L,
9659245075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,45083L,45084L,
9659345085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,45093L,45094L,
9659445095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,45103L,45104L,
9659545105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,45113L,45114L,
9659645115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,45123L,45124L,
9659745125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,45133L,45134L,
9659845135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,45143L,45144L,
9659945145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,45153L,45154L,
9660045155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,45163L,45164L,
9660145165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,45173L,45174L,
9660245175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,45183L,45184L,
9660345185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,45193L,45194L,
9660445195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,45203L,45204L,
9660545205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,45213L,45214L,
9660645215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,45223L,45224L,
9660745225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,45233L,45234L,
9660845235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,45243L,45244L,
9660945245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,45253L,45254L,
9661045255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,45263L,45264L,
9661145265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,45273L,45274L,
9661245275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,45283L,45284L,
9661345285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,45293L,45294L,
9661445295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,45303L,45304L,
9661545305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,45313L,45314L,
9661645315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,45323L,45324L,
9661745325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,45333L,45334L,
9661845335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,45343L,45344L,
9661945345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,45353L,45354L,
9662045355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,45363L,45364L,
9662145365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,45373L,45374L,
9662245375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,45383L,45384L,
9662345385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,45393L,45394L,
9662445395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,45403L,45404L,
9662545405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,45413L,45414L,
9662645415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,45423L,45424L,
9662745425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,45433L,45434L,
9662845435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,45443L,45444L,
9662945445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,45453L,45454L,
9663045455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,45463L,45464L,
9663145465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,45473L,45474L,
9663245475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,45483L,45484L,
9663345485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,45493L,45494L,
9663445495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,45503L,45504L,
9663545505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,45513L,45514L,
9663645515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,45523L,45524L,
9663745525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,45533L,45534L,
9663845535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,45543L,45544L,
9663945545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,45553L,45554L,
9664045555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,45563L,45564L,
9664145565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,45573L,45574L,
9664245575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,45583L,45584L,
9664345585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,45593L,45594L,
9664445595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,45603L,45604L,
9664545605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,45613L,45614L,
9664645615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,45623L,45624L,
9664745625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,45633L,45634L,
9664845635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,45643L,45644L,
9664945645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,45653L,45654L,
9665045655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,45663L,45664L,
9665145665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,45673L,45674L,
9665245675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,45683L,45684L,
9665345685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,45693L,45694L,
9665445695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,45703L,45704L,
9665545705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,45713L,45714L,
9665645715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,45723L,45724L,
9665745725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,45733L,45734L,
9665845735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,45743L,45744L,
9665945745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,45753L,45754L,
9666045755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,45763L,45764L,
9666145765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,45773L,45774L,
9666245775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,45783L,45784L,
9666345785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,45793L,45794L,
9666445795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,45803L,45804L,
9666545805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,45813L,45814L,
9666645815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,45823L,45824L,
9666745825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,45833L,45834L,
9666845835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,45843L,45844L,
9666945845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,45853L,45854L,
9667045855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,45863L,45864L,
9667145865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,45873L,45874L,
9667245875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,45883L,45884L,
9667345885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,45893L,45894L,
9667445895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,45903L,45904L,
9667545905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,45913L,45914L,
9667645915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,45923L,45924L,
9667745925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,45933L,45934L,
9667845935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,45943L,45944L,
9667945945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,45953L,45954L,
9668045955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,45963L,45964L,
9668145965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,45973L,45974L,
9668245975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,45983L,45984L,
9668345985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,45993L,45994L,
9668445995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,46003L,46004L,
9668546005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,46013L,46014L,
9668646015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,46023L,46024L,
9668746025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,46033L,46034L,
9668846035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,46043L,46044L,
9668946045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,46053L,46054L,
9669046055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,46063L,46064L,
9669146065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,46073L,46074L,
9669246075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,46083L,46084L,
9669346085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,46093L,46094L,
9669446095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,46103L,46104L,
9669546105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,46113L,46114L,
9669646115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,46123L,46124L,
9669746125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,46133L,46134L,
9669846135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,46143L,46144L,
9669946145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,46153L,46154L,
9670046155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,46163L,46164L,
9670146165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,46173L,46174L,
9670246175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,46183L,46184L,
9670346185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,46193L,46194L,
9670446195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,46203L,46204L,
9670546205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,46213L,46214L,
9670646215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,46223L,46224L,
9670746225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,46233L,46234L,
9670846235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,46243L,46244L,
9670946245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,46253L,46254L,
9671046255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,46263L,46264L,
9671146265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,46273L,46274L,
9671246275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,46283L,46284L,
9671346285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,46293L,46294L,
9671446295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,46303L,46304L,
9671546305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,46313L,46314L,
9671646315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,46323L,46324L,
9671746325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,46333L,46334L,
9671846335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,46343L,46344L,
9671946345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,46353L,46354L,
9672046355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,46363L,46364L,
9672146365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,46373L,46374L,
9672246375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,46383L,46384L,
9672346385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,46393L,46394L,
9672446395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,46403L,46404L,
9672546405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,46413L,46414L,
9672646415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,46423L,46424L,
9672746425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,46433L,46434L,
9672846435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,46443L,46444L,
9672946445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,46453L,46454L,
9673046455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,46463L,46464L,
9673146465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,46473L,46474L,
9673246475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,46483L,46484L,
9673346485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,46493L,46494L,
9673446495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,46503L,46504L,
9673546505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,46513L,46514L,
9673646515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,46523L,46524L,
9673746525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,46533L,46534L,
9673846535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,46543L,46544L,
9673946545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,46553L,46554L,
9674046555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,46563L,46564L,
9674146565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,46573L,46574L,
9674246575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,46583L,46584L,
9674346585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,46593L,46594L,
9674446595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,46603L,46604L,
9674546605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,46613L,46614L,
9674646615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,46623L,46624L,
9674746625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,46633L,46634L,
9674846635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,46643L,46644L,
9674946645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,46653L,46654L,
9675046655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,46663L,46664L,
9675146665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,46673L,46674L,
9675246675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,46683L,46684L,
9675346685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,46693L,46694L,
9675446695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,46703L,46704L,
9675546705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,46713L,46714L,
9675646715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,46723L,46724L,
9675746725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,46733L,46734L,
9675846735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,46743L,46744L,
9675946745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,46753L,46754L,
9676046755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,46763L,46764L,
9676146765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,46773L,46774L,
9676246775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,46783L,46784L,
9676346785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,46793L,46794L,
9676446795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,46803L,46804L,
9676546805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,46813L,46814L,
9676646815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,46823L,46824L,
9676746825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,46833L,46834L,
9676846835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,46843L,46844L,
9676946845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,46853L,46854L,
9677046855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,46863L,46864L,
9677146865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,46873L,46874L,
9677246875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,46883L,46884L,
9677346885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,46893L,46894L,
9677446895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,46903L,46904L,
9677546905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,46913L,46914L,
9677646915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,46923L,46924L,
9677746925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,46933L,46934L,
9677846935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,46943L,46944L,
9677946945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,46953L,46954L,
9678046955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,46963L,46964L,
9678146965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,46973L,46974L,
9678246975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,46983L,46984L,
9678346985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,46993L,46994L,
9678446995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,47003L,47004L,
9678547005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,47013L,47014L,
9678647015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,47023L,47024L,
9678747025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,47033L,47034L,
9678847035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,47043L,47044L,
9678947045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,47053L,47054L,
9679047055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,47063L,47064L,
9679147065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,47073L,47074L,
9679247075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,47083L,47084L,
9679347085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,47093L,47094L,
9679447095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,47103L,47104L,
9679547105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,47113L,47114L,
9679647115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,47123L,47124L,
9679747125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,47133L,47134L,
9679847135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,47143L,47144L,
9679947145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,47153L,47154L,
9680047155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,47163L,47164L,
9680147165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,47173L,47174L,
9680247175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,47183L,47184L,
9680347185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,47193L,47194L,
9680447195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,47203L,47204L,
9680547205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,47213L,47214L,
9680647215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,47223L,47224L,
9680747225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,47233L,47234L,
9680847235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,47243L,47244L,
9680947245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,47253L,47254L,
9681047255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,47263L,47264L,
9681147265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,47273L,47274L,
9681247275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,47283L,47284L,
9681347285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,47293L,47294L,
9681447295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,47303L,47304L,
9681547305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,47313L,47314L,
9681647315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,47323L,47324L,
9681747325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,47333L,47334L,
9681847335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,47343L,47344L,
9681947345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,47353L,47354L,
9682047355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,47363L,47364L,
9682147365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,47373L,47374L,
9682247375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,47383L,47384L,
9682347385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,47393L,47394L,
9682447395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,47403L,47404L,
9682547405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,47413L,47414L,
9682647415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,47423L,47424L,
9682747425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,47433L,47434L,
9682847435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,47443L,47444L,
9682947445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,47453L,47454L,
9683047455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,47463L,47464L,
9683147465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,47473L,47474L,
9683247475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,47483L,47484L,
9683347485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,47493L,47494L,
9683447495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,47503L,47504L,
9683547505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,47513L,47514L,
9683647515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,47523L,47524L,
9683747525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,47533L,47534L,
9683847535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,47543L,47544L,
9683947545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,47553L,47554L,
9684047555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,47563L,47564L,
9684147565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,47573L,47574L,
9684247575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,47583L,47584L,
9684347585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,47593L,47594L,
9684447595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,47603L,47604L,
9684547605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,47613L,47614L,
9684647615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,47623L,47624L,
9684747625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,47633L,47634L,
9684847635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,47643L,47644L,
9684947645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,47653L,47654L,
9685047655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,47663L,47664L,
9685147665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,47673L,47674L,
9685247675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,47683L,47684L,
9685347685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,47693L,47694L,
9685447695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,47703L,47704L,
9685547705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,47713L,47714L,
9685647715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,47723L,47724L,
9685747725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,47733L,47734L,
9685847735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,47743L,47744L,
9685947745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,47753L,47754L,
9686047755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,47763L,47764L,
9686147765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,47773L,47774L,
9686247775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,47783L,47784L,
9686347785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,47793L,47794L,
9686447795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,47803L,47804L,
9686547805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,47813L,47814L,
9686647815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,47823L,47824L,
9686747825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,47833L,47834L,
9686847835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,47843L,47844L,
9686947845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,47853L,47854L,
9687047855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,47863L,47864L,
9687147865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,47873L,47874L,
9687247875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,47883L,47884L,
9687347885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,47893L,47894L,
9687447895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,47903L,47904L,
9687547905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,47913L,47914L,
9687647915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,47923L,47924L,
9687747925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,47933L,47934L,
9687847935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,47943L,47944L,
9687947945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,47953L,47954L,
9688047955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,47963L,47964L,
9688147965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,47973L,47974L,
9688247975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,47983L,47984L,
9688347985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,47993L,47994L,
9688447995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,48003L,48004L,
9688548005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,48013L,48014L,
9688648015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,48023L,48024L,
9688748025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,48033L,48034L,
9688848035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,48043L,48044L,
9688948045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,48053L,48054L,
9689048055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,48063L,48064L,
9689148065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,48073L,48074L,
9689248075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,48083L,48084L,
9689348085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,48093L,48094L,
9689448095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,48103L,48104L,
9689548105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,48113L,48114L,
9689648115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,48123L,48124L,
9689748125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,48133L,48134L,
9689848135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,48143L,48144L,
9689948145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,48153L,48154L,
9690048155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,48163L,48164L,
9690148165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,48173L,48174L,
9690248175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,48183L,48184L,
9690348185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,48193L,48194L,
9690448195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,48203L,48204L,
9690548205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,48213L,48214L,
9690648215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,48223L,48224L,
9690748225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,48233L,48234L,
9690848235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,48243L,48244L,
9690948245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,48253L,48254L,
9691048255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,48263L,48264L,
9691148265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,48273L,48274L,
9691248275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,48283L,48284L,
9691348285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,48293L,48294L,
9691448295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,48303L,48304L,
9691548305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,48313L,48314L,
9691648315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,48323L,48324L,
9691748325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,48333L,48334L,
9691848335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,48343L,48344L,
9691948345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,48353L,48354L,
9692048355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,48363L,48364L,
9692148365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,48373L,48374L,
9692248375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,48383L,48384L,
9692348385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,48393L,48394L,
9692448395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,48403L,48404L,
9692548405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,48413L,48414L,
9692648415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,48423L,48424L,
9692748425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,48433L,48434L,
9692848435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,48443L,48444L,
9692948445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,48453L,48454L,
9693048455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,48463L,48464L,
9693148465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,48473L,48474L,
9693248475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,48483L,48484L,
9693348485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,48493L,48494L,
9693448495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,48503L,48504L,
9693548505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,48513L,48514L,
9693648515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,48523L,48524L,
9693748525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,48533L,48534L,
9693848535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,48543L,48544L,
9693948545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,48553L,48554L,
9694048555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,48563L,48564L,
9694148565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,48573L,48574L,
9694248575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,48583L,48584L,
9694348585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,48593L,48594L,
9694448595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,48603L,48604L,
9694548605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,48613L,48614L,
9694648615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,48623L,48624L,
9694748625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,48633L,48634L,
9694848635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,48643L,48644L,
9694948645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,48653L,48654L,
9695048655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,48663L,48664L,
9695148665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,48673L,48674L,
9695248675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,48683L,48684L,
9695348685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,48693L,48694L,
9695448695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,48703L,48704L,
9695548705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,48713L,48714L,
9695648715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,48723L,48724L,
9695748725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,48733L,48734L,
9695848735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,48743L,48744L,
9695948745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,48753L,48754L,
9696048755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,48763L,48764L,
9696148765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,48773L,48774L,
9696248775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,48783L,48784L,
9696348785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,48793L,48794L,
9696448795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,48803L,48804L,
9696548805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,48813L,48814L,
9696648815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,48823L,48824L,
9696748825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,48833L,48834L,
9696848835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,48843L,48844L,
9696948845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,48853L,48854L,
9697048855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,48863L,48864L,
9697148865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,48873L,48874L,
9697248875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,48883L,48884L,
9697348885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,48893L,48894L,
9697448895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,48903L,48904L,
9697548905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,48913L,48914L,
9697648915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,48923L,48924L,
9697748925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,48933L,48934L,
9697848935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,48943L,48944L,
9697948945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,48953L,48954L,
9698048955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,48963L,48964L,
9698148965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,48973L,48974L,
9698248975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,48983L,48984L,
9698348985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,48993L,48994L,
9698448995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,49003L,49004L,
9698549005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,49013L,49014L,
9698649015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,49023L,49024L,
9698749025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,49033L,49034L,
9698849035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,49043L,49044L,
9698949045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,49053L,49054L,
9699049055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,49063L,49064L,
9699149065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,49073L,49074L,
9699249075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,49083L,49084L,
9699349085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,49093L,49094L,
9699449095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,49103L,49104L,
9699549105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,49113L,49114L,
9699649115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,49123L,49124L,
9699749125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,49133L,49134L,
9699849135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,49143L,49144L,
9699949145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,49153L,49154L,
9700049155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,49163L,49164L,
9700149165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,49173L,49174L,
9700249175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,49183L,49184L,
9700349185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,49193L,49194L,
9700449195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,49203L,49204L,
9700549205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,49213L,49214L,
9700649215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,49223L,49224L,
9700749225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,49233L,49234L,
9700849235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,49243L,49244L,
9700949245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,49253L,49254L,
9701049255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,49263L,49264L,
9701149265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,49273L,49274L,
9701249275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,49283L,49284L,
9701349285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,49293L,49294L,
9701449295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,49303L,49304L,
9701549305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,49313L,49314L,
9701649315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,49323L,49324L,
9701749325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,49333L,49334L,
9701849335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,49343L,49344L,
9701949345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,49353L,49354L,
9702049355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,49363L,49364L,
9702149365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,49373L,49374L,
9702249375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,49383L,49384L,
9702349385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,49393L,49394L,
9702449395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,49403L,49404L,
9702549405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,49413L,49414L,
9702649415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,49423L,49424L,
9702749425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,49433L,49434L,
9702849435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,49443L,49444L,
9702949445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,49453L,49454L,
9703049455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,49463L,49464L,
9703149465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,49473L,49474L,
9703249475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,49483L,49484L,
9703349485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,49493L,49494L,
9703449495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,49503L,49504L,
9703549505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,49513L,49514L,
9703649515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,49523L,49524L,
9703749525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,49533L,49534L,
9703849535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,49543L,49544L,
9703949545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,49553L,49554L,
9704049555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,49563L,49564L,
9704149565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,49573L,49574L,
9704249575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,49583L,49584L,
9704349585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,49593L,49594L,
9704449595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,49603L,49604L,
9704549605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,49613L,49614L,
9704649615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,49623L,49624L,
9704749625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,49633L,49634L,
9704849635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,49643L,49644L,
9704949645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,49653L,49654L,
9705049655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,49663L,49664L,
9705149665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,49673L,49674L,
9705249675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,49683L,49684L,
9705349685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,49693L,49694L,
9705449695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,49703L,49704L,
9705549705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,49713L,49714L,
9705649715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,49723L,49724L,
9705749725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,49733L,49734L,
9705849735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,49743L,49744L,
9705949745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,49753L,49754L,
9706049755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,49763L,49764L,
9706149765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,49773L,49774L,
9706249775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,49783L,49784L,
9706349785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,49793L,49794L,
9706449795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,49803L,49804L,
9706549805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,49813L,49814L,
9706649815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,49823L,49824L,
9706749825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,49833L,49834L,
9706849835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,49843L,49844L,
9706949845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,49853L,49854L,
9707049855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,49863L,49864L,
9707149865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,49873L,49874L,
9707249875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,49883L,49884L,
9707349885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,49893L,49894L,
9707449895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,49903L,49904L,
9707549905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,49913L,49914L,
9707649915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,49923L,49924L,
9707749925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,49933L,49934L,
9707849935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,49943L,49944L,
9707949945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,49953L,49954L,
9708049955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,49963L,49964L,
9708149965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,49973L,49974L,
9708249975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,49983L,49984L,
9708349985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,49993L,49994L,
9708449995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,50003L,50004L,
9708550005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,50013L,50014L,
9708650015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,50023L,50024L,
9708750025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,50033L,50034L,
9708850035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,50043L,50044L,
9708950045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,50053L,50054L,
9709050055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,50063L,50064L,
9709150065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,50073L,50074L,
9709250075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,50083L,50084L,
9709350085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,50093L,50094L,
9709450095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,50103L,50104L,
9709550105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,50113L,50114L,
9709650115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,50123L,50124L,
9709750125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,50133L,50134L,
9709850135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,50143L,50144L,
9709950145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,50153L,50154L,
9710050155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,50163L,50164L,
9710150165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,50173L,50174L,
9710250175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,50183L,50184L,
9710350185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,50193L,50194L,
9710450195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,50203L,50204L,
9710550205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,50213L,50214L,
9710650215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,50223L,50224L,
9710750225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,50233L,50234L,
9710850235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,50243L,50244L,
9710950245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,50253L,50254L,
9711050255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,50263L,50264L,
9711150265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,50273L,50274L,
9711250275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,50283L,50284L,
9711350285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,50293L,50294L,
9711450295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,50303L,50304L,
9711550305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,50313L,50314L,
9711650315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,50323L,50324L,
9711750325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,50333L,50334L,
9711850335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,50343L,50344L,
9711950345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,50353L,50354L,
9712050355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,50363L,50364L,
9712150365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,50373L,50374L,
9712250375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,50383L,50384L,
9712350385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,50393L,50394L,
9712450395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,50403L,50404L,
9712550405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,50413L,50414L,
9712650415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,50423L,50424L,
9712750425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,50433L,50434L,
9712850435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,50443L,50444L,
9712950445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,50453L,50454L,
9713050455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,50463L,50464L,
9713150465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,50473L,50474L,
9713250475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,50483L,50484L,
9713350485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,50493L,50494L,
9713450495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,50503L,50504L,
9713550505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,50513L,50514L,
9713650515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,50523L,50524L,
9713750525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,50533L,50534L,
9713850535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,50543L,50544L,
9713950545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,50553L,50554L,
9714050555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,50563L,50564L,
9714150565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,50573L,50574L,
9714250575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,50583L,50584L,
9714350585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,50593L,50594L,
9714450595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,50603L,50604L,
9714550605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,50613L,50614L,
9714650615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,50623L,50624L,
9714750625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,50633L,50634L,
9714850635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,50643L,50644L,
9714950645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,50653L,50654L,
9715050655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,50663L,50664L,
9715150665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,50673L,50674L,
9715250675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,50683L,50684L,
9715350685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,50693L,50694L,
9715450695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,50703L,50704L,
9715550705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,50713L,50714L,
9715650715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,50723L,50724L,
9715750725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,50733L,50734L,
9715850735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,50743L,50744L,
9715950745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,50753L,50754L,
9716050755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,50763L,50764L,
9716150765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,50773L,50774L,
9716250775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,50783L,50784L,
9716350785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,50793L,50794L,
9716450795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,50803L,50804L,
9716550805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,50813L,50814L,
9716650815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,50823L,50824L,
9716750825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,50833L,50834L,
9716850835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,50843L,50844L,
9716950845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,50853L,50854L,
9717050855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,50863L,50864L,
9717150865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,50873L,50874L,
9717250875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,50883L,50884L,
9717350885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,50893L,50894L,
9717450895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,50903L,50904L,
9717550905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,50913L,50914L,
9717650915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,50923L,50924L,
9717750925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,50933L,50934L,
9717850935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,50943L,50944L,
9717950945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,50953L,50954L,
9718050955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,50963L,50964L,
9718150965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,50973L,50974L,
9718250975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,50983L,50984L,
9718350985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,50993L,50994L,
9718450995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,51003L,51004L,
9718551005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,51013L,51014L,
9718651015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,51023L,51024L,
9718751025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,51033L,51034L,
9718851035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,51043L,51044L,
9718951045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,51053L,51054L,
9719051055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,51063L,51064L,
9719151065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,51073L,51074L,
9719251075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,51083L,51084L,
9719351085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,51093L,51094L,
9719451095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,51103L,51104L,
9719551105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,51113L,51114L,
9719651115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,51123L,51124L,
9719751125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,51133L,51134L,
9719851135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,51143L,51144L,
9719951145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,51153L,51154L,
9720051155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,51163L,51164L,
9720151165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,51173L,51174L,
9720251175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,51183L,51184L,
9720351185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,51193L,51194L,
9720451195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,51203L,51204L,
9720551205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,51213L,51214L,
9720651215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,51223L,51224L,
9720751225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,51233L,51234L,
9720851235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,51243L,51244L,
9720951245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,51253L,51254L,
9721051255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,51263L,51264L,
9721151265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,51273L,51274L,
9721251275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,51283L,51284L,
9721351285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,51293L,51294L,
9721451295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,51303L,51304L,
9721551305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,51313L,51314L,
9721651315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,51323L,51324L,
9721751325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,51333L,51334L,
9721851335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,51343L,51344L,
9721951345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,51353L,51354L,
9722051355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,51363L,51364L,
9722151365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,51373L,51374L,
9722251375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,51383L,51384L,
9722351385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,51393L,51394L,
9722451395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,51403L,51404L,
9722551405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,51413L,51414L,
9722651415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,51423L,51424L,
9722751425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,51433L,51434L,
9722851435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,51443L,51444L,
9722951445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,51453L,51454L,
9723051455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,51463L,51464L,
9723151465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,51473L,51474L,
9723251475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,51483L,51484L,
9723351485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,51493L,51494L,
9723451495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,51503L,51504L,
9723551505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,51513L,51514L,
9723651515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,51523L,51524L,
9723751525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,51533L,51534L,
9723851535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,51543L,51544L,
9723951545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,51553L,51554L,
9724051555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,51563L,51564L,
9724151565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,51573L,51574L,
9724251575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,51583L,51584L,
9724351585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,51593L,51594L,
9724451595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,51603L,51604L,
9724551605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,51613L,51614L,
9724651615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,51623L,51624L,
9724751625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,51633L,51634L,
9724851635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,51643L,51644L,
9724951645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,51653L,51654L,
9725051655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,51663L,51664L,
9725151665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,51673L,51674L,
9725251675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,51683L,51684L,
9725351685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,51693L,51694L,
9725451695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,51703L,51704L,
9725551705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,51713L,51714L,
9725651715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,51723L,51724L,
9725751725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,51733L,51734L,
9725851735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,51743L,51744L,
9725951745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,51753L,51754L,
9726051755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,51763L,51764L,
9726151765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,51773L,51774L,
9726251775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,51783L,51784L,
9726351785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,51793L,51794L,
9726451795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,51803L,51804L,
9726551805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,51813L,51814L,
9726651815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,51823L,51824L,
9726751825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,51833L,51834L,
9726851835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,51843L,51844L,
9726951845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,51853L,51854L,
9727051855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,51863L,51864L,
9727151865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,51873L,51874L,
9727251875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,51883L,51884L,
9727351885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,51893L,51894L,
9727451895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,51903L,51904L,
9727551905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,51913L,51914L,
9727651915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,51923L,51924L,
9727751925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,51933L,51934L,
9727851935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,51943L,51944L,
9727951945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,51953L,51954L,
9728051955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,51963L,51964L,
9728151965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,51973L,51974L,
9728251975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,51983L,51984L,
9728351985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,51993L,51994L,
9728451995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,52003L,52004L,
9728552005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,52013L,52014L,
9728652015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,52023L,52024L,
9728752025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,52033L,52034L,
9728852035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,52043L,52044L,
9728952045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,52053L,52054L,
9729052055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,52063L,52064L,
9729152065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,52073L,52074L,
9729252075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,52083L,52084L,
9729352085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,52093L,52094L,
9729452095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,52103L,52104L,
9729552105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,52113L,52114L,
9729652115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,52123L,52124L,
9729752125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,52133L,52134L,
9729852135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,52143L,52144L,
9729952145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,52153L,52154L,
9730052155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,52163L,52164L,
9730152165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,52173L,52174L,
9730252175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,52183L,52184L,
9730352185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,52193L,52194L,
9730452195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,52203L,52204L,
9730552205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,52213L,52214L,
9730652215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,52223L,52224L,
9730752225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,52233L,52234L,
9730852235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,52243L,52244L,
9730952245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,52253L,52254L,
9731052255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,52263L,52264L,
9731152265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,52273L,52274L,
9731252275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,52283L,52284L,
9731352285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,52293L,52294L,
9731452295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,52303L,52304L,
9731552305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,52313L,52314L,
9731652315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,52323L,52324L,
9731752325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,52333L,52334L,
9731852335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,52343L,52344L,
9731952345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,52353L,52354L,
9732052355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,52363L,52364L,
9732152365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,52373L,52374L,
9732252375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,52383L,52384L,
9732352385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,52393L,52394L,
9732452395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,52403L,52404L,
9732552405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,52413L,52414L,
9732652415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,52423L,52424L,
9732752425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,52433L,52434L,
9732852435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,52443L,52444L,
9732952445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,52453L,52454L,
9733052455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,52463L,52464L,
9733152465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,52473L,52474L,
9733252475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,52483L,52484L,
9733352485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,52493L,52494L,
9733452495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,52503L,52504L,
9733552505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,52513L,52514L,
9733652515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,52523L,52524L,
9733752525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,52533L,52534L,
9733852535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,52543L,52544L,
9733952545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,52553L,52554L,
9734052555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,52563L,52564L,
9734152565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,52573L,52574L,
9734252575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,52583L,52584L,
9734352585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,52593L,52594L,
9734452595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,52603L,52604L,
9734552605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,52613L,52614L,
9734652615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,52623L,52624L,
9734752625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,52633L,52634L,
9734852635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,52643L,52644L,
9734952645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,52653L,52654L,
9735052655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,52663L,52664L,
9735152665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,52673L,52674L,
9735252675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,52683L,52684L,
9735352685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,52693L,52694L,
9735452695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,52703L,52704L,
9735552705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,52713L,52714L,
9735652715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,52723L,52724L,
9735752725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,52733L,52734L,
9735852735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,52743L,52744L,
9735952745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,52753L,52754L,
9736052755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,52763L,52764L,
9736152765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,52773L,52774L,
9736252775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,52783L,52784L,
9736352785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,52793L,52794L,
9736452795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,52803L,52804L,
9736552805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,52813L,52814L,
9736652815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,52823L,52824L,
9736752825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,52833L,52834L,
9736852835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,52843L,52844L,
9736952845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,52853L,52854L,
9737052855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,52863L,52864L,
9737152865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,52873L,52874L,
9737252875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,52883L,52884L,
9737352885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,52893L,52894L,
9737452895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,52903L,52904L,
9737552905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,52913L,52914L,
9737652915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,52923L,52924L,
9737752925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,52933L,52934L,
9737852935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,52943L,52944L,
9737952945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,52953L,52954L,
9738052955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,52963L,52964L,
9738152965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,52973L,52974L,
9738252975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,52983L,52984L,
9738352985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,52993L,52994L,
9738452995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,53003L,53004L,
9738553005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,53013L,53014L,
9738653015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,53023L,53024L,
9738753025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,53033L,53034L,
9738853035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,53043L,53044L,
9738953045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,53053L,53054L,
9739053055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,53063L,53064L,
9739153065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,53073L,53074L,
9739253075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,53083L,53084L,
9739353085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,53093L,53094L,
9739453095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,53103L,53104L,
9739553105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,53113L,53114L,
9739653115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,53123L,53124L,
9739753125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,53133L,53134L,
9739853135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,53143L,53144L,
9739953145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,53153L,53154L,
9740053155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,53163L,53164L,
9740153165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,53173L,53174L,
9740253175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,53183L,53184L,
9740353185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,53193L,53194L,
9740453195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,53203L,53204L,
9740553205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,53213L,53214L,
9740653215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,53223L,53224L,
9740753225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,53233L,53234L,
9740853235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,53243L,53244L,
9740953245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,53253L,53254L,
9741053255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,53263L,53264L,
9741153265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,53273L,53274L,
9741253275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,53283L,53284L,
9741353285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,53293L,53294L,
9741453295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,53303L,53304L,
9741553305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,53313L,53314L,
9741653315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,53323L,53324L,
9741753325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,53333L,53334L,
9741853335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,53343L,53344L,
9741953345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,53353L,53354L,
9742053355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,53363L,53364L,
9742153365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,53373L,53374L,
9742253375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,53383L,53384L,
9742353385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,53393L,53394L,
9742453395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,53403L,53404L,
9742553405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,53413L,53414L,
9742653415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,53423L,53424L,
9742753425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,53433L,53434L,
9742853435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,53443L,53444L,
9742953445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,53453L,53454L,
9743053455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,53463L,53464L,
9743153465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,53473L,53474L,
9743253475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,53483L,53484L,
9743353485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,53493L,53494L,
9743453495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,53503L,53504L,
9743553505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,53513L,53514L,
9743653515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,53523L,53524L,
9743753525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,53533L,53534L,
9743853535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,53543L,53544L,
9743953545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,53553L,53554L,
9744053555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,53563L,53564L,
9744153565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,53573L,53574L,
9744253575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,53583L,53584L,
9744353585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,53593L,53594L,
9744453595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,53603L,53604L,
9744553605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,53613L,53614L,
9744653615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,53623L,53624L,
9744753625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,53633L,53634L,
9744853635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,53643L,53644L,
9744953645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,53653L,53654L,
9745053655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,53663L,53664L,
9745153665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,53673L,53674L,
9745253675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,53683L,53684L,
9745353685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,53693L,53694L,
9745453695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,53703L,53704L,
9745553705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,53713L,53714L,
9745653715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,53723L,53724L,
9745753725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,53733L,53734L,
9745853735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,53743L,53744L,
9745953745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,53753L,53754L,
9746053755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,53763L,53764L,
9746153765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,53773L,53774L,
9746253775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,53783L,53784L,
9746353785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,53793L,53794L,
9746453795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,53803L,53804L,
9746553805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,53813L,53814L,
9746653815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,53823L,53824L,
9746753825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,53833L,53834L,
9746853835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,53843L,53844L,
9746953845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,53853L,53854L,
9747053855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,53863L,53864L,
9747153865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,53873L,53874L,
9747253875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,53883L,53884L,
9747353885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,53893L,53894L,
9747453895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,53903L,53904L,
9747553905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,53913L,53914L,
9747653915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,53923L,53924L,
9747753925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,53933L,53934L,
9747853935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,53943L,53944L,
9747953945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,53953L,53954L,
9748053955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,53963L,53964L,
9748153965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,53973L,53974L,
9748253975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,53983L,53984L,
9748353985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,53993L,53994L,
9748453995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,54003L,54004L,
9748554005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,54013L,54014L,
9748654015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,54023L,54024L,
9748754025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,54033L,54034L,
9748854035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,54043L,54044L,
9748954045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,54053L,54054L,
9749054055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,54063L,54064L,
9749154065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,54073L,54074L,
9749254075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,54083L,54084L,
9749354085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,54093L,54094L,
9749454095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,54103L,54104L,
9749554105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,54113L,54114L,
9749654115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,54123L,54124L,
9749754125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,54133L,54134L,
9749854135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,54143L,54144L,
9749954145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,54153L,54154L,
9750054155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,54163L,54164L,
9750154165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,54173L,54174L,
9750254175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,54183L,54184L,
9750354185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,54193L,54194L,
9750454195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,54203L,54204L,
9750554205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,54213L,54214L,
9750654215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,54223L,54224L,
9750754225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,54233L,54234L,
9750854235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,54243L,54244L,
9750954245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,54253L,54254L,
9751054255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,54263L,54264L,
9751154265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,54273L,54274L,
9751254275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,54283L,54284L,
9751354285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,54293L,54294L,
9751454295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,54303L,54304L,
9751554305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,54313L,54314L,
9751654315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,54323L,54324L,
9751754325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,54333L,54334L,
9751854335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,54343L,54344L,
9751954345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,54353L,54354L,
9752054355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,54363L,54364L,
9752154365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,54373L,54374L,
9752254375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,54383L,54384L,
9752354385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,54393L,54394L,
9752454395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,54403L,54404L,
9752554405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,54413L,54414L,
9752654415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,54423L,54424L,
9752754425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,54433L,54434L,
9752854435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,54443L,54444L,
9752954445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,54453L,54454L,
9753054455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,54463L,54464L,
9753154465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,54473L,54474L,
9753254475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,54483L,54484L,
9753354485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,54493L,54494L,
9753454495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,54503L,54504L,
9753554505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,54513L,54514L,
9753654515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,54523L,54524L,
9753754525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,54533L,54534L,
9753854535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,54543L,54544L,
9753954545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,54553L,54554L,
9754054555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,54563L,54564L,
9754154565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,54573L,54574L,
9754254575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,54583L,54584L,
9754354585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,54593L,54594L,
9754454595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,54603L,54604L,
9754554605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,54613L,54614L,
9754654615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,54623L,54624L,
9754754625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,54633L,54634L,
9754854635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,54643L,54644L,
9754954645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,54653L,54654L,
9755054655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,54663L,54664L,
9755154665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,54673L,54674L,
9755254675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,54683L,54684L,
9755354685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,54693L,54694L,
9755454695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,54703L,54704L,
9755554705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,54713L,54714L,
9755654715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,54723L,54724L,
9755754725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,54733L,54734L,
9755854735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,54743L,54744L,
9755954745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,54753L,54754L,
9756054755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,54763L,54764L,
9756154765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,54773L,54774L,
9756254775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,54783L,54784L,
9756354785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,54793L,54794L,
9756454795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,54803L,54804L,
9756554805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,54813L,54814L,
9756654815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,54823L,54824L,
9756754825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,54833L,54834L,
9756854835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,54843L,54844L,
9756954845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,54853L,54854L,
9757054855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,54863L,54864L,
9757154865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,54873L,54874L,
9757254875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,54883L,54884L,
9757354885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,54893L,54894L,
9757454895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,54903L,54904L,
9757554905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,54913L,54914L,
9757654915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,54923L,54924L,
9757754925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,54933L,54934L,
9757854935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,54943L,54944L,
9757954945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,54953L,54954L,
9758054955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,54963L,54964L,
9758154965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,54973L,54974L,
9758254975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,54983L,54984L,
9758354985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,54993L,54994L,
9758454995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,55003L,55004L,
9758555005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,55013L,55014L,
9758655015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,55023L,55024L,
9758755025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,55033L,55034L,
9758855035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,55043L,55044L,
9758955045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,55053L,55054L,
9759055055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,55063L,55064L,
9759155065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,55073L,55074L,
9759255075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,55083L,55084L,
9759355085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,55093L,55094L,
9759455095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,55103L,55104L,
9759555105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,55113L,55114L,
9759655115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,55123L,55124L,
9759755125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,55133L,55134L,
9759855135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,55143L,55144L,
9759955145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,55153L,55154L,
9760055155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,55163L,55164L,
9760155165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,55173L,55174L,
9760255175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,55183L,55184L,
9760355185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,55193L,55194L,
9760455195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,55203L,55204L,
9760555205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,55213L,55214L,
9760655215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,55223L,55224L,
9760755225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,55233L,55234L,
9760855235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,55243L,55244L,
9760955245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,55253L,55254L,
9761055255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,55263L,55264L,
9761155265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,55273L,55274L,
9761255275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,55283L,55284L,
9761355285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,55293L,55294L,
9761455295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,55303L,55304L,
9761555305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,55313L,55314L,
9761655315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,55323L,55324L,
9761755325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,55333L,55334L,
9761855335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,55343L,55344L,
9761955345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,55353L,55354L,
9762055355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,55363L,55364L,
9762155365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,55373L,55374L,
9762255375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,55383L,55384L,
9762355385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,55393L,55394L,
9762455395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,55403L,55404L,
9762555405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,55413L,55414L,
9762655415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,55423L,55424L,
9762755425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,55433L,55434L,
9762855435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,55443L,55444L,
9762955445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,55453L,55454L,
9763055455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,55463L,55464L,
9763155465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,55473L,55474L,
9763255475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,55483L,55484L,
9763355485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,55493L,55494L,
9763455495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,55503L,55504L,
9763555505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,55513L,55514L,
9763655515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,55523L,55524L,
9763755525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,55533L,55534L,
9763855535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,55543L,55544L,
9763955545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,55553L,55554L,
9764055555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,55563L,55564L,
9764155565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,55573L,55574L,
9764255575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,55583L,55584L,
9764355585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,55593L,55594L,
9764455595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,55603L,55604L,
9764555605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,55613L,55614L,
9764655615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,55623L,55624L,
9764755625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,55633L,55634L,
9764855635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,55643L,55644L,
9764955645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,55653L,55654L,
9765055655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,55663L,55664L,
9765155665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,55673L,55674L,
9765255675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,55683L,55684L,
9765355685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,55693L,55694L,
9765455695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,55703L,55704L,
9765555705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,55713L,55714L,
9765655715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,55723L,55724L,
9765755725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,55733L,55734L,
9765855735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,55743L,55744L,
9765955745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,55753L,55754L,
9766055755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,55763L,55764L,
9766155765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,55773L,55774L,
9766255775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,55783L,55784L,
9766355785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,55793L,55794L,
9766455795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,55803L,55804L,
9766555805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,55813L,55814L,
9766655815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,55823L,55824L,
9766755825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,55833L,55834L,
9766855835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,55843L,55844L,
9766955845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,55853L,55854L,
9767055855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,55863L,55864L,
9767155865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,55873L,55874L,
9767255875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,55883L,55884L,
9767355885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,55893L,55894L,
9767455895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,55903L,55904L,
9767555905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,55913L,55914L,
9767655915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,55923L,55924L,
9767755925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,55933L,55934L,
9767855935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,55943L,55944L,
9767955945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,55953L,55954L,
9768055955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,55963L,55964L,
9768155965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,55973L,55974L,
9768255975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,55983L,55984L,
9768355985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,55993L,55994L,
9768455995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,56003L,56004L,
9768556005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,56013L,56014L,
9768656015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,56023L,56024L,
9768756025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,56033L,56034L,
9768856035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,56043L,56044L,
9768956045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,56053L,56054L,
9769056055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,56063L,56064L,
9769156065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,56073L,56074L,
9769256075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,56083L,56084L,
9769356085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,56093L,56094L,
9769456095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,56103L,56104L,
9769556105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,56113L,56114L,
9769656115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,56123L,56124L,
9769756125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,56133L,56134L,
9769856135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,56143L,56144L,
9769956145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,56153L,56154L,
9770056155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,56163L,56164L,
9770156165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,56173L,56174L,
9770256175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,56183L,56184L,
9770356185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,56193L,56194L,
9770456195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,56203L,56204L,
9770556205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,56213L,56214L,
9770656215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,56223L,56224L,
9770756225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,56233L,56234L,
9770856235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,56243L,56244L,
9770956245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,56253L,56254L,
9771056255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,56263L,56264L,
9771156265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,56273L,56274L,
9771256275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,56283L,56284L,
9771356285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,56293L,56294L,
9771456295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,56303L,56304L,
9771556305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,56313L,56314L,
9771656315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,56323L,56324L,
9771756325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,56333L,56334L,
9771856335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,56343L,56344L,
9771956345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,56353L,56354L,
9772056355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,56363L,56364L,
9772156365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,56373L,56374L,
9772256375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,56383L,56384L,
9772356385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,56393L,56394L,
9772456395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,56403L,56404L,
9772556405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,56413L,56414L,
9772656415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,56423L,56424L,
9772756425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,56433L,56434L,
9772856435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,56443L,56444L,
9772956445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,56453L,56454L,
9773056455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,56463L,56464L,
9773156465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,56473L,56474L,
9773256475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,56483L,56484L,
9773356485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,56493L,56494L,
9773456495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,56503L,56504L,
9773556505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,56513L,56514L,
9773656515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,56523L,56524L,
9773756525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,56533L,56534L,
9773856535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,56543L,56544L,
9773956545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,56553L,56554L,
9774056555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,56563L,56564L,
9774156565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,56573L,56574L,
9774256575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,56583L,56584L,
9774356585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,56593L,56594L,
9774456595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,56603L,56604L,
9774556605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,56613L,56614L,
9774656615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,56623L,56624L,
9774756625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,56633L,56634L,
9774856635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,56643L,56644L,
9774956645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,56653L,56654L,
9775056655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,56663L,56664L,
9775156665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,56673L,56674L,
9775256675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,56683L,56684L,
9775356685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,56693L,56694L,
9775456695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,56703L,56704L,
9775556705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,56713L,56714L,
9775656715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,56723L,56724L,
9775756725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,56733L,56734L,
9775856735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,56743L,56744L,
9775956745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,56753L,56754L,
9776056755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,56763L,56764L,
9776156765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,56773L,56774L,
9776256775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,56783L,56784L,
9776356785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,56793L,56794L,
9776456795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,56803L,56804L,
9776556805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,56813L,56814L,
9776656815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,56823L,56824L,
9776756825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,56833L,56834L,
9776856835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,56843L,56844L,
9776956845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,56853L,56854L,
9777056855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,56863L,56864L,
9777156865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,56873L,56874L,
9777256875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,56883L,56884L,
9777356885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,56893L,56894L,
9777456895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,56903L,56904L,
9777556905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,56913L,56914L,
9777656915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,56923L,56924L,
9777756925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,56933L,56934L,
9777856935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,56943L,56944L,
9777956945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,56953L,56954L,
9778056955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,56963L,56964L,
9778156965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,56973L,56974L,
9778256975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,56983L,56984L,
9778356985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,56993L,56994L,
9778456995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,57003L,57004L,
9778557005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,57013L,57014L,
9778657015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,57023L,57024L,
9778757025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,57033L,57034L,
9778857035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,57043L,57044L,
9778957045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,57053L,57054L,
9779057055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,57063L,57064L,
9779157065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,57073L,57074L,
9779257075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,57083L,57084L,
9779357085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,57093L,57094L,
9779457095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,57103L,57104L,
9779557105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,57113L,57114L,
9779657115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,57123L,57124L,
9779757125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,57133L,57134L,
9779857135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,57143L,57144L,
9779957145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,57153L,57154L,
9780057155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,57163L,57164L,
9780157165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,57173L,57174L,
9780257175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,57183L,57184L,
9780357185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,57193L,57194L,
9780457195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,57203L,57204L,
9780557205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,57213L,57214L,
9780657215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,57223L,57224L,
9780757225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,57233L,57234L,
9780857235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,57243L,57244L,
9780957245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,57253L,57254L,
9781057255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,57263L,57264L,
9781157265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,57273L,57274L,
9781257275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,57283L,57284L,
9781357285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,57293L,57294L,
9781457295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,57303L,57304L,
9781557305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,57313L,57314L,
9781657315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,57323L,57324L,
9781757325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,57333L,57334L,
9781857335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,57343L,57344L,
9781957345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,57353L,57354L,
9782057355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,57363L,57364L,
9782157365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,57373L,57374L,
9782257375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,57383L,57384L,
9782357385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,57393L,57394L,
9782457395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,57403L,57404L,
9782557405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,57413L,57414L,
9782657415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,57423L,57424L,
9782757425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,57433L,57434L,
9782857435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,57443L,57444L,
9782957445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,57453L,57454L,
9783057455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,57463L,57464L,
9783157465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,57473L,57474L,
9783257475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,57483L,57484L,
9783357485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,57493L,57494L,
9783457495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,57503L,57504L,
9783557505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,57513L,57514L,
9783657515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,57523L,57524L,
9783757525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,57533L,57534L,
9783857535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,57543L,57544L,
9783957545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,57553L,57554L,
9784057555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,57563L,57564L,
9784157565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,57573L,57574L,
9784257575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,57583L,57584L,
9784357585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,57593L,57594L,
9784457595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,57603L,57604L,
9784557605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,57613L,57614L,
9784657615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,57623L,57624L,
9784757625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,57633L,57634L,
9784857635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,57643L,57644L,
9784957645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,57653L,57654L,
9785057655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,57663L,57664L,
9785157665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,57673L,57674L,
9785257675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,57683L,57684L,
9785357685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,57693L,57694L,
9785457695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,57703L,57704L,
9785557705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,57713L,57714L,
9785657715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,57723L,57724L,
9785757725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,57733L,57734L,
9785857735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,57743L,57744L,
9785957745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,57753L,57754L,
9786057755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,57763L,57764L,
9786157765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,57773L,57774L,
9786257775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,57783L,57784L,
9786357785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,57793L,57794L,
9786457795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,57803L,57804L,
9786557805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,57813L,57814L,
9786657815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,57823L,57824L,
9786757825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,57833L,57834L,
9786857835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,57843L,57844L,
9786957845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,57853L,57854L,
9787057855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,57863L,57864L,
9787157865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,57873L,57874L,
9787257875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,57883L,57884L,
9787357885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,57893L,57894L,
9787457895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,57903L,57904L,
9787557905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,57913L,57914L,
9787657915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,57923L,57924L,
9787757925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,57933L,57934L,
9787857935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,57943L,57944L,
9787957945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,57953L,57954L,
9788057955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,57963L,57964L,
9788157965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,57973L,57974L,
9788257975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,57983L,57984L,
9788357985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,57993L,57994L,
9788457995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,58003L,58004L,
9788558005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,58013L,58014L,
9788658015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,58023L,58024L,
9788758025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,58033L,58034L,
9788858035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,58043L,58044L,
9788958045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,58053L,58054L,
9789058055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,58063L,58064L,
9789158065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,58073L,58074L,
9789258075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,58083L,58084L,
9789358085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,58093L,58094L,
9789458095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,58103L,58104L,
9789558105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,58113L,58114L,
9789658115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,58123L,58124L,
9789758125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,58133L,58134L,
9789858135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,58143L,58144L,
9789958145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,58153L,58154L,
9790058155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,58163L,58164L,
9790158165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,58173L,58174L,
9790258175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,58183L,58184L,
9790358185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,58193L,58194L,
9790458195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,58203L,58204L,
9790558205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,58213L,58214L,
9790658215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,58223L,58224L,
9790758225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,58233L,58234L,
9790858235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,58243L,58244L,
9790958245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,58253L,58254L,
9791058255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,58263L,58264L,
9791158265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,58273L,58274L,
9791258275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,58283L,58284L,
9791358285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,58293L,58294L,
9791458295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,58303L,58304L,
9791558305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,58313L,58314L,
9791658315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,58323L,58324L,
9791758325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,58333L,58334L,
9791858335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,58343L,58344L,
9791958345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,58353L,58354L,
9792058355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,58363L,58364L,
9792158365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,58373L,58374L,
9792258375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,58383L,58384L,
9792358385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,58393L,58394L,
9792458395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,58403L,58404L,
9792558405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,58413L,58414L,
9792658415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,58423L,58424L,
9792758425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,58433L,58434L,
9792858435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,58443L,58444L,
9792958445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,58453L,58454L,
9793058455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,58463L,58464L,
9793158465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,58473L,58474L,
9793258475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,58483L,58484L,
9793358485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,58493L,58494L,
9793458495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,58503L,58504L,
9793558505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,58513L,58514L,
9793658515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,58523L,58524L,
9793758525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,58533L,58534L,
9793858535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,58543L,58544L,
9793958545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,58553L,58554L,
9794058555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,58563L,58564L,
9794158565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,58573L,58574L,
9794258575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,58583L,58584L,
9794358585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,58593L,58594L,
9794458595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,58603L,58604L,
9794558605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,58613L,58614L,
9794658615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,58623L,58624L,
9794758625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,58633L,58634L,
9794858635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,58643L,58644L,
9794958645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,58653L,58654L,
9795058655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,58663L,58664L,
9795158665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,58673L,58674L,
9795258675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,58683L,58684L,
9795358685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,58693L,58694L,
9795458695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,58703L,58704L,
9795558705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,58713L,58714L,
9795658715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,58723L,58724L,
9795758725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,58733L,58734L,
9795858735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,58743L,58744L,
9795958745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,58753L,58754L,
9796058755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,58763L,58764L,
9796158765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,58773L,58774L,
9796258775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,58783L,58784L,
9796358785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,58793L,58794L,
9796458795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,58803L,58804L,
9796558805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,58813L,58814L,
9796658815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,58823L,58824L,
9796758825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,58833L,58834L,
9796858835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,58843L,58844L,
9796958845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,58853L,58854L,
9797058855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,58863L,58864L,
9797158865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,58873L,58874L,
9797258875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,58883L,58884L,
9797358885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,58893L,58894L,
9797458895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,58903L,58904L,
9797558905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,58913L,58914L,
9797658915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,58923L,58924L,
9797758925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,58933L,58934L,
9797858935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,58943L,58944L,
9797958945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,58953L,58954L,
9798058955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,58963L,58964L,
9798158965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,58973L,58974L,
9798258975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,58983L,58984L,
9798358985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,58993L,58994L,
9798458995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,59003L,59004L,
9798559005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,59013L,59014L,
9798659015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,59023L,59024L,
9798759025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,59033L,59034L,
9798859035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,59043L,59044L,
9798959045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,59053L,59054L,
9799059055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,59063L,59064L,
9799159065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,59073L,59074L,
9799259075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,59083L,59084L,
9799359085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,59093L,59094L,
9799459095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,59103L,59104L,
9799559105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,59113L,59114L,
9799659115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,59123L,59124L,
9799759125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,59133L,59134L,
9799859135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,59143L,59144L,
9799959145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,59153L,59154L,
9800059155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,59163L,59164L,
9800159165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,59173L,59174L,
9800259175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,59183L,59184L,
9800359185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,59193L,59194L,
9800459195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,59203L,59204L,
9800559205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,59213L,59214L,
9800659215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,59223L,59224L,
9800759225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,59233L,59234L,
9800859235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,59243L,59244L,
9800959245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,59253L,59254L,
9801059255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,59263L,59264L,
9801159265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,59273L,59274L,
9801259275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,59283L,59284L,
9801359285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,59293L,59294L,
9801459295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,59303L,59304L,
9801559305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,59313L,59314L,
9801659315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,59323L,59324L,
9801759325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,59333L,59334L,
9801859335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,59343L,59344L,
9801959345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,59353L,59354L,
9802059355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,59363L,59364L,
9802159365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,59373L,59374L,
9802259375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,59383L,59384L,
9802359385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,59393L,59394L,
9802459395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,59403L,59404L,
9802559405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,59413L,59414L,
9802659415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,59423L,59424L,
9802759425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,59433L,59434L,
9802859435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,59443L,59444L,
9802959445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,59453L,59454L,
9803059455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,59463L,59464L,
9803159465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,59473L,59474L,
9803259475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,59483L,59484L,
9803359485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,59493L,59494L,
9803459495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,59503L,59504L,
9803559505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,59513L,59514L,
9803659515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,59523L,59524L,
9803759525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,59533L,59534L,
9803859535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,59543L,59544L,
9803959545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,59553L,59554L,
9804059555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,59563L,59564L,
9804159565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,59573L,59574L,
9804259575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,59583L,59584L,
9804359585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,59593L,59594L,
9804459595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,59603L,59604L,
9804559605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,59613L,59614L,
9804659615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,59623L,59624L,
9804759625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,59633L,59634L,
9804859635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,59643L,59644L,
9804959645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,59653L,59654L,
9805059655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,59663L,59664L,
9805159665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,59673L,59674L,
9805259675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,59683L,59684L,
9805359685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,59693L,59694L,
9805459695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,59703L,59704L,
9805559705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,59713L,59714L,
9805659715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,59723L,59724L,
9805759725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,59733L,59734L,
9805859735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,59743L,59744L,
9805959745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,59753L,59754L,
9806059755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,59763L,59764L,
9806159765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,59773L,59774L,
9806259775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,59783L,59784L,
9806359785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,59793L,59794L,
9806459795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,59803L,59804L,
9806559805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,59813L,59814L,
9806659815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,59823L,59824L,
9806759825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,59833L,59834L,
9806859835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,59843L,59844L,
9806959845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,59853L,59854L,
9807059855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,59863L,59864L,
9807159865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,59873L,59874L,
9807259875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,59883L,59884L,
9807359885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,59893L,59894L,
9807459895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,59903L,59904L,
9807559905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,59913L,59914L,
9807659915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,59923L,59924L,
9807759925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,59933L,59934L,
9807859935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,59943L,59944L,
9807959945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,59953L,59954L,
9808059955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,59963L,59964L,
9808159965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,59973L,59974L,
9808259975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,59983L,59984L,
9808359985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,59993L,59994L,
9808459995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,60003L,60004L,
9808560005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,60013L,60014L,
9808660015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,60023L,60024L,
9808760025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,60033L,60034L,
9808860035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,60043L,60044L,
9808960045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,60053L,60054L,
9809060055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,60063L,60064L,
9809160065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,60073L,60074L,
9809260075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,60083L,60084L,
9809360085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,60093L,60094L,
9809460095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,60103L,60104L,
9809560105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,60113L,60114L,
9809660115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,60123L,60124L,
9809760125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,60133L,60134L,
9809860135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,60143L,60144L,
9809960145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,60153L,60154L,
9810060155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,60163L,60164L,
9810160165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,60173L,60174L,
9810260175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,60183L,60184L,
9810360185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,60193L,60194L,
9810460195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,60203L,60204L,
9810560205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,60213L,60214L,
9810660215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,60223L,60224L,
9810760225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,60233L,60234L,
9810860235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,60243L,60244L,
9810960245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,60253L,60254L,
9811060255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,60263L,60264L,
9811160265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,60273L,60274L,
9811260275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,60283L,60284L,
9811360285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,60293L,60294L,
9811460295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,60303L,60304L,
9811560305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,60313L,60314L,
9811660315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,60323L,60324L,
9811760325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,60333L,60334L,
9811860335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,60343L,60344L,
9811960345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,60353L,60354L,
9812060355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,60363L,60364L,
9812160365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,60373L,60374L,
9812260375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,60383L,60384L,
9812360385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,60393L,60394L,
9812460395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,60403L,60404L,
9812560405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,60413L,60414L,
9812660415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,60423L,60424L,
9812760425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,60433L,60434L,
9812860435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,60443L,60444L,
9812960445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,60453L,60454L,
9813060455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,60463L,60464L,
9813160465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,60473L,60474L,
9813260475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,60483L,60484L,
9813360485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,60493L,60494L,
9813460495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,60503L,60504L,
9813560505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,60513L,60514L,
9813660515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,60523L,60524L,
9813760525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,60533L,60534L,
9813860535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,60543L,60544L,
9813960545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,60553L,60554L,
9814060555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,60563L,60564L,
9814160565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,60573L,60574L,
9814260575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,60583L,60584L,
9814360585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,60593L,60594L,
9814460595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,60603L,60604L,
9814560605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,60613L,60614L,
9814660615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,60623L,60624L,
9814760625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,60633L,60634L,
9814860635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,60643L,60644L,
9814960645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,60653L,60654L,
9815060655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,60663L,60664L,
9815160665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,60673L,60674L,
9815260675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,60683L,60684L,
9815360685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,60693L,60694L,
9815460695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,60703L,60704L,
9815560705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,60713L,60714L,
9815660715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,60723L,60724L,
9815760725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,60733L,60734L,
9815860735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,60743L,60744L,
9815960745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,60753L,60754L,
9816060755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,60763L,60764L,
9816160765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,60773L,60774L,
9816260775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,60783L,60784L,
9816360785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,60793L,60794L,
9816460795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,60803L,60804L,
9816560805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,60813L,60814L,
9816660815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,60823L,60824L,
9816760825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,60833L,60834L,
9816860835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,60843L,60844L,
9816960845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,60853L,60854L,
9817060855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,60863L,60864L,
9817160865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,60873L,60874L,
9817260875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,60883L,60884L,
9817360885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,60893L,60894L,
9817460895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,60903L,60904L,
9817560905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,60913L,60914L,
9817660915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,60923L,60924L,
9817760925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,60933L,60934L,
9817860935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,60943L,60944L,
9817960945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,60953L,60954L,
9818060955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,60963L,60964L,
9818160965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,60973L,60974L,
9818260975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,60983L,60984L,
9818360985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,60993L,60994L,
9818460995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,61003L,61004L,
9818561005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,61013L,61014L,
9818661015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,61023L,61024L,
9818761025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,61033L,61034L,
9818861035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,61043L,61044L,
9818961045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,61053L,61054L,
9819061055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,61063L,61064L,
9819161065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,61073L,61074L,
9819261075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,61083L,61084L,
9819361085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,61093L,61094L,
9819461095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,61103L,61104L,
9819561105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,61113L,61114L,
9819661115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,61123L,61124L,
9819761125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,61133L,61134L,
9819861135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,61143L,61144L,
9819961145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,61153L,61154L,
9820061155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,61163L,61164L,
9820161165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,61173L,61174L,
9820261175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,61183L,61184L,
9820361185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,61193L,61194L,
9820461195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,61203L,61204L,
9820561205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,61213L,61214L,
9820661215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,61223L,61224L,
9820761225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,61233L,61234L,
9820861235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,61243L,61244L,
9820961245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,61253L,61254L,
9821061255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,61263L,61264L,
9821161265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,61273L,61274L,
9821261275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,61283L,61284L,
9821361285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,61293L,61294L,
9821461295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,61303L,61304L,
9821561305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,61313L,61314L,
9821661315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,61323L,61324L,
9821761325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,61333L,61334L,
9821861335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,61343L,61344L,
9821961345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,61353L,61354L,
9822061355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,61363L,61364L,
9822161365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,61373L,61374L,
9822261375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,61383L,61384L,
9822361385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,61393L,61394L,
9822461395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,61403L,61404L,
9822561405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,61413L,61414L,
9822661415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,61423L,61424L,
9822761425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,61433L,61434L,
9822861435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,61443L,61444L,
9822961445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,61453L,61454L,
9823061455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,61463L,61464L,
9823161465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,61473L,61474L,
9823261475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,61483L,61484L,
9823361485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,61493L,61494L,
9823461495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,61503L,61504L,
9823561505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,61513L,61514L,
9823661515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,61523L,61524L,
9823761525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,61533L,61534L,
9823861535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,61543L,61544L,
9823961545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,61553L,61554L,
9824061555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,61563L,61564L,
9824161565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,61573L,61574L,
9824261575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,61583L,61584L,
9824361585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,61593L,61594L,
9824461595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,61603L,61604L,
9824561605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,61613L,61614L,
9824661615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,61623L,61624L,
9824761625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,61633L,61634L,
9824861635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,61643L,61644L,
9824961645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,61653L,61654L,
9825061655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,61663L,61664L,
9825161665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,61673L,61674L,
9825261675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,61683L,61684L,
9825361685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,61693L,61694L,
9825461695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,61703L,61704L,
9825561705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,61713L,61714L,
9825661715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,61723L,61724L,
9825761725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,61733L,61734L,
9825861735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,61743L,61744L,
9825961745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,61753L,61754L,
9826061755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,61763L,61764L,
9826161765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,61773L,61774L,
9826261775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,61783L,61784L,
9826361785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,61793L,61794L,
9826461795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,61803L,61804L,
9826561805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,61813L,61814L,
9826661815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,61823L,61824L,
9826761825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,61833L,61834L,
9826861835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,61843L,61844L,
9826961845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,61853L,61854L,
9827061855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,61863L,61864L,
9827161865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,61873L,61874L,
9827261875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,61883L,61884L,
9827361885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,61893L,61894L,
9827461895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,61903L,61904L,
9827561905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,61913L,61914L,
9827661915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,61923L,61924L,
9827761925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,61933L,61934L,
9827861935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,61943L,61944L,
9827961945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,61953L,61954L,
9828061955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,61963L,61964L,
9828161965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,61973L,61974L,
9828261975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,61983L,61984L,
9828361985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,61993L,61994L,
9828461995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,62003L,62004L,
9828562005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,62013L,62014L,
9828662015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,62023L,62024L,
9828762025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,62033L,62034L,
9828862035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,62043L,62044L,
9828962045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,62053L,62054L,
9829062055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,62063L,62064L,
9829162065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,62073L,62074L,
9829262075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,62083L,62084L,
9829362085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,62093L,62094L,
9829462095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,62103L,62104L,
9829562105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,62113L,62114L,
9829662115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,62123L,62124L,
9829762125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,62133L,62134L,
9829862135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,62143L,62144L,
9829962145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,62153L,62154L,
9830062155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,62163L,62164L,
9830162165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,62173L,62174L,
9830262175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,62183L,62184L,
9830362185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,62193L,62194L,
9830462195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,62203L,62204L,
9830562205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,62213L,62214L,
9830662215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,62223L,62224L,
9830762225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,62233L,62234L,
9830862235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,62243L,62244L,
9830962245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,62253L,62254L,
9831062255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,62263L,62264L,
9831162265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,62273L,62274L,
9831262275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,62283L,62284L,
9831362285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,62293L,62294L,
9831462295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,62303L,62304L,
9831562305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,62313L,62314L,
9831662315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,62323L,62324L,
9831762325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,62333L,62334L,
9831862335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,62343L,62344L,
9831962345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,62353L,62354L,
9832062355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,62363L,62364L,
9832162365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,62373L,62374L,
9832262375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,62383L,62384L,
9832362385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,62393L,62394L,
9832462395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,62403L,62404L,
9832562405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,62413L,62414L,
9832662415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,62423L,62424L,
9832762425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,62433L,62434L,
9832862435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,62443L,62444L,
9832962445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,62453L,62454L,
9833062455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,62463L,62464L,
9833162465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,62473L,62474L,
9833262475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,62483L,62484L,
9833362485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,62493L,62494L,
9833462495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,62503L,62504L,
9833562505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,62513L,62514L,
9833662515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,62523L,62524L,
9833762525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,62533L,62534L,
9833862535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,62543L,62544L,
9833962545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,62553L,62554L,
9834062555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,62563L,62564L,
9834162565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,62573L,62574L,
9834262575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,62583L,62584L,
9834362585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,62593L,62594L,
9834462595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,62603L,62604L,
9834562605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,62613L,62614L,
9834662615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,62623L,62624L,
9834762625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,62633L,62634L,
9834862635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,62643L,62644L,
9834962645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,62653L,62654L,
9835062655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,62663L,62664L,
9835162665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,62673L,62674L,
9835262675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,62683L,62684L,
9835362685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,62693L,62694L,
9835462695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,62703L,62704L,
9835562705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,62713L,62714L,
9835662715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,62723L,62724L,
9835762725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,62733L,62734L,
9835862735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,62743L,62744L,
9835962745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,62753L,62754L,
9836062755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,62763L,62764L,
9836162765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,62773L,62774L,
9836262775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,62783L,62784L,
9836362785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,62793L,62794L,
9836462795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,62803L,62804L,
9836562805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,62813L,62814L,
9836662815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,62823L,62824L,
9836762825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,62833L,62834L,
9836862835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,62843L,62844L,
9836962845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,62853L,62854L,
9837062855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,62863L,62864L,
9837162865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,62873L,62874L,
9837262875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,62883L,62884L,
9837362885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,62893L,62894L,
9837462895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,62903L,62904L,
9837562905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,62913L,62914L,
9837662915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,62923L,62924L,
9837762925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,62933L,62934L,
9837862935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,62943L,62944L,
9837962945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,62953L,62954L,
9838062955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,62963L,62964L,
9838162965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,62973L,62974L,
9838262975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,62983L,62984L,
9838362985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,62993L,62994L,
9838462995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,63003L,63004L,
9838563005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,63013L,63014L,
9838663015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,63023L,63024L,
9838763025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,63033L,63034L,
9838863035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,63043L,63044L,
9838963045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,63053L,63054L,
9839063055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,63063L,63064L,
9839163065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,63073L,63074L,
9839263075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,63083L,63084L,
9839363085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,63093L,63094L,
9839463095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,63103L,63104L,
9839563105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,63113L,63114L,
9839663115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,63123L,63124L,
9839763125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,63133L,63134L,
9839863135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,63143L,63144L,
9839963145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,63153L,63154L,
9840063155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,63163L,63164L,
9840163165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,63173L,63174L,
9840263175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,63183L,63184L,
9840363185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,63193L,63194L,
9840463195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,63203L,63204L,
9840563205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,63213L,63214L,
9840663215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,63223L,63224L,
9840763225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,63233L,63234L,
9840863235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,63243L,63244L,
9840963245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,63253L,63254L,
9841063255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,63263L,63264L,
9841163265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,63273L,63274L,
9841263275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,63283L,63284L,
9841363285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,63293L,63294L,
9841463295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,63303L,63304L,
9841563305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,63313L,63314L,
9841663315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,63323L,63324L,
9841763325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,63333L,63334L,
9841863335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,63343L,63344L,
9841963345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,63353L,63354L,
9842063355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,63363L,63364L,
9842163365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,63373L,63374L,
9842263375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,63383L,63384L,
9842363385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,63393L,63394L,
9842463395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,63403L,63404L,
9842563405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,63413L,63414L,
9842663415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,63423L,63424L,
9842763425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,63433L,63434L,
9842863435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,63443L,63444L,
9842963445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,63453L,63454L,
9843063455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,63463L,63464L,
9843163465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,63473L,63474L,
9843263475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,63483L,63484L,
9843363485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,63493L,63494L,
9843463495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,63503L,63504L,
9843563505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,63513L,63514L,
9843663515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,63523L,63524L,
9843763525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,63533L,63534L,
9843863535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,63543L,63544L,
9843963545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,63553L,63554L,
9844063555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,63563L,63564L,
9844163565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,63573L,63574L,
9844263575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,63583L,63584L,
9844363585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,63593L,63594L,
9844463595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,63603L,63604L,
9844563605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,63613L,63614L,
9844663615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,63623L,63624L,
9844763625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,63633L,63634L,
9844863635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,63643L,63644L,
9844963645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,63653L,63654L,
9845063655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,63663L,63664L,
9845163665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,63673L,63674L,
9845263675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,63683L,63684L,
9845363685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,63693L,63694L,
9845463695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,63703L,63704L,
9845563705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,63713L,63714L,
9845663715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,63723L,63724L,
9845763725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,63733L,63734L,
9845863735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,63743L,63744L,
9845963745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,63753L,63754L,
9846063755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,63763L,63764L,
9846163765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,63773L,63774L,
9846263775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,63783L,63784L,
9846363785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,63793L,63794L,
9846463795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,63803L,63804L,
9846563805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,63813L,63814L,
9846663815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,63823L,63824L,
9846763825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,63833L,63834L,
9846863835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,63843L,63844L,
9846963845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,63853L,63854L,
9847063855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,63863L,63864L,
9847163865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,63873L,63874L,
9847263875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,63883L,63884L,
9847363885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,63893L,63894L,
9847463895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,63903L,63904L,
9847563905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,63913L,63914L,
9847663915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,63923L,63924L,
9847763925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,63933L,63934L,
9847863935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,63943L,63944L,
9847963945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,63953L,63954L,
9848063955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,63963L,63964L,
9848163965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,63973L,63974L,
9848263975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,63983L,63984L,
9848363985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,63993L,63994L,
9848463995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,64003L,64004L,
9848564005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,64013L,64014L,
9848664015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,64023L,64024L,
9848764025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,64033L,64034L,
9848864035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,64043L,64044L,
9848964045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,64053L,64054L,
9849064055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,64063L,64064L,
9849164065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,64073L,64074L,
9849264075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,64083L,64084L,
9849364085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,64093L,64094L,
9849464095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,64103L,64104L,
9849564105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,64113L,64114L,
9849664115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,64123L,64124L,
9849764125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,64133L,64134L,
9849864135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,64143L,64144L,
9849964145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,64153L,64154L,
9850064155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,64163L,64164L,
9850164165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,64173L,64174L,
9850264175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,64183L,64184L,
9850364185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,64193L,64194L,
9850464195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,64203L,64204L,
9850564205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,64213L,64214L,
9850664215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,64223L,64224L,
9850764225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,64233L,64234L,
9850864235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,64243L,64244L,
9850964245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,64253L,64254L,
9851064255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,64263L,64264L,
9851164265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,64273L,64274L,
9851264275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,64283L,64284L,
9851364285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,64293L,64294L,
9851464295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,64303L,64304L,
9851564305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,64313L,64314L,
9851664315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,64323L,64324L,
9851764325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,64333L,64334L,
9851864335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,64343L,64344L,
9851964345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,64353L,64354L,
9852064355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,64363L,64364L,
9852164365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,64373L,64374L,
9852264375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,64383L,64384L,
9852364385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,64393L,64394L,
9852464395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,64403L,64404L,
9852564405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,64413L,64414L,
9852664415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,64423L,64424L,
9852764425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,64433L,64434L,
9852864435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,64443L,64444L,
9852964445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,64453L,64454L,
9853064455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,64463L,64464L,
9853164465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,64473L,64474L,
9853264475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,64483L,64484L,
9853364485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,64493L,64494L,
9853464495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,64503L,64504L,
9853564505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,64513L,64514L,
9853664515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,64523L,64524L,
9853764525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,64533L,64534L,
9853864535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,64543L,64544L,
9853964545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,64553L,64554L,
9854064555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,64563L,64564L,
9854164565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,64573L,64574L,
9854264575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,64583L,64584L,
9854364585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,64593L,64594L,
9854464595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,64603L,64604L,
9854564605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,64613L,64614L,
9854664615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,64623L,64624L,
9854764625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,64633L,64634L,
9854864635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,64643L,64644L,
9854964645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,64653L,64654L,
9855064655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,64663L,64664L,
9855164665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,64673L,64674L,
9855264675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,64683L,64684L,
9855364685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,64693L,64694L,
9855464695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,64703L,64704L,
9855564705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,64713L,64714L,
9855664715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,64723L,64724L,
9855764725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,64733L,64734L,
9855864735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,64743L,64744L,
9855964745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,64753L,64754L,
9856064755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,64763L,64764L,
9856164765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,64773L,64774L,
9856264775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,64783L,64784L,
9856364785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,64793L,64794L,
9856464795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,64803L,64804L,
9856564805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,64813L,64814L,
9856664815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,64823L,64824L,
9856764825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,64833L,64834L,
9856864835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,64843L,64844L,
9856964845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,64853L,64854L,
9857064855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,64863L,64864L,
9857164865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,64873L,64874L,
9857264875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,64883L,64884L,
9857364885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,64893L,64894L,
9857464895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,64903L,64904L,
9857564905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,64913L,64914L,
9857664915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,64923L,64924L,
9857764925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,64933L,64934L,
9857864935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,64943L,64944L,
9857964945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,64953L,64954L,
9858064955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,64963L,64964L,
9858164965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,64973L,64974L,
9858264975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,64983L,64984L,
9858364985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,64993L,64994L,
9858464995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,65003L,65004L,
9858565005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,65013L,65014L,
9858665015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,65023L,65024L,
9858765025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,65033L,65034L,
9858865035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,65043L,65044L,
9858965045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,65053L,65054L,
9859065055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,65063L,65064L,
9859165065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,65073L,65074L,
9859265075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,65083L,65084L,
9859365085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,65093L,65094L,
9859465095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,65103L,65104L,
9859565105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,65113L,65114L,
9859665115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,65123L,65124L,
9859765125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,65133L,65134L,
9859865135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,65143L,65144L,
9859965145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,65153L,65154L,
9860065155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,65163L,65164L,
9860165165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,65173L,65174L,
9860265175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,65183L,65184L,
9860365185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,65193L,65194L,
9860465195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,65203L,65204L,
9860565205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,65213L,65214L,
9860665215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,65223L,65224L,
9860765225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,65233L,65234L,
9860865235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,65243L,65244L,
9860965245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,65253L,65254L,
9861065255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,65263L,65264L,
9861165265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,65273L,65274L,
9861265275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,65283L,65284L,
9861365285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,65293L,65294L,
9861465295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,65303L,65304L,
9861565305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,65313L,65314L,
9861665315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L,
9861765325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L,
9861865335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,65343L,65344L,
9861965313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,
9862065323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,
9862165333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,65373L,65374L,
9862265375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,65383L,65384L,
9862365385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,65393L,65394L,
9862465395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,65403L,65404L,
9862565405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,65413L,65414L,
9862665415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,65423L,65424L,
9862765425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,65433L,65434L,
9862865435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,65443L,65444L,
9862965445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,65453L,65454L,
9863065455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,65463L,65464L,
9863165465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,65473L,65474L,
9863265475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,65483L,65484L,
9863365485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,65493L,65494L,
9863465495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,65503L,65504L,
9863565505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,65513L,65514L,
9863665515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,65523L,65524L,
9863765525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,65533L,65534L,
9863865535L,
98639};
98640#endif
98641
98642#if defined(DUK_USE_REGEXP_CANON_BITMAP)
98643/*
98644 * Automatically generated by extract_caseconv.py, do not edit!
98645 */
98646
98647const duk_uint8_t duk_unicode_re_canon_bitmap[256] = {
9864823,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,63,254,255,127,
98649255,255,255,255,255,255,255,255,231,231,0,16,255,227,255,255,63,255,255,
98650255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255,
98651255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98652255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98653255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98654255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98655255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98656255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98657227,129,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255,
98658255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98659255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98660255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
98661255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251,
98662};
98663#endif
98664#line 1 "duk_util_bitdecoder.c"
98665/*
98666 * Bitstream decoder.
98667 */
98668
98669/* #include duk_internal.h -> already included */
98670
98671/* Decode 'bits' bits from the input stream (bits must be 1...24).
98672 * When reading past bitstream end, zeroes are shifted in. The result
98673 * is signed to match duk_bd_decode_flagged.
98674 */
98675DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
98676 duk_small_int_t shift;
98677 duk_uint32_t mask;
98678 duk_uint32_t tmp;
98679
98680 /* Note: cannot read more than 24 bits without possibly shifting top bits out.
98681 * Fixable, but adds complexity.
98682 */
98683 DUK_ASSERT(bits >= 1 && bits <= 24);
98684
98685 while (ctx->currbits < bits) {
98686#if 0
98687 DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
98688 (long) bits, (long) ctx->currbits));
98689#endif
98690 ctx->currval <<= 8;
98691 if (ctx->offset < ctx->length) {
98692 /* If ctx->offset >= ctx->length, we "shift zeroes in"
98693 * instead of croaking.
98694 */
98695 ctx->currval |= ctx->data[ctx->offset++];
98696 }
98697 ctx->currbits += 8;
98698 }
98699#if 0
98700 DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
98701 (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
98702#endif
98703
98704 /* Extract 'top' bits of currval; note that the extracted bits do not need
98705 * to be cleared, we just ignore them on next round.
98706 */
98707 shift = ctx->currbits - bits;
98708 mask = (((duk_uint32_t) 1U) << bits) - 1U;
98709 tmp = (ctx->currval >> shift) & mask;
98710 ctx->currbits = shift; /* remaining */
98711
98712#if 0
98713 DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
98714 (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
98715#endif
98716
98717 return tmp;
98718}
98719
98720DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
98721 return (duk_small_uint_t) duk_bd_decode(ctx, 1);
98722}
98723
98724/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
98725 * default value.
98726 */
98727DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) {
98728 if (duk_bd_decode_flag(ctx)) {
98729 return duk_bd_decode(ctx, bits);
98730 } else {
98731 return def_value;
98732 }
98733}
98734
98735/* Signed variant, allows negative marker value. */
98736DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
98737 return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value);
98738}
98739
98740/* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */
98741DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) {
98742 duk_small_uint_t t;
98743
98744 /* The bit encoding choices here are based on manual testing against
98745 * the actual varuints generated by genbuiltins.py.
98746 */
98747 switch (duk_bd_decode(ctx, 2)) {
98748 case 0:
98749 return 0; /* [0,0] */
98750 case 1:
98751 return duk_bd_decode(ctx, 2) + 1; /* [1,4] */
98752 case 2:
98753 return duk_bd_decode(ctx, 5) + 5; /* [5,36] */
98754 default:
98755 t = duk_bd_decode(ctx, 7);
98756 if (t == 0) {
98757 return duk_bd_decode(ctx, 20);
98758 }
98759 return (t - 1) + 37; /* [37,163] */
98760 }
98761}
98762
98763/* Decode a bit packed string from a custom format used by genbuiltins.py.
98764 * This function is here because it's used for both heap and thread inits.
98765 * Caller must supply the output buffer whose size is NOT checked!
98766 */
98767
98768#define DUK__BITPACK_LETTER_LIMIT 26
98769#define DUK__BITPACK_LOOKUP1 26
98770#define DUK__BITPACK_LOOKUP2 27
98771#define DUK__BITPACK_SWITCH1 28
98772#define DUK__BITPACK_SWITCH 29
98773#define DUK__BITPACK_UNUSED1 30
98774#define DUK__BITPACK_EIGHTBIT 31
98775
98776DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = {
98777 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
98778 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
98779 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE,
98780 0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
98781};
98782
98783DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) {
98784 duk_small_uint_t len;
98785 duk_small_uint_t mode;
98786 duk_small_uint_t t;
98787 duk_small_uint_t i;
98788
98789 len = duk_bd_decode(bd, 5);
98790 if (len == 31) {
98791 len = duk_bd_decode(bd, 8); /* Support up to 256 bytes; rare. */
98792 }
98793
98794 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
98795 for (i = 0; i < len; i++) {
98796 t = duk_bd_decode(bd, 5);
98797 if (t < DUK__BITPACK_LETTER_LIMIT) {
98798 t = t + DUK_ASC_UC_A + mode;
98799 } else if (t == DUK__BITPACK_LOOKUP1) {
98800 t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)];
98801 } else if (t == DUK__BITPACK_LOOKUP2) {
98802 t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)];
98803 } else if (t == DUK__BITPACK_SWITCH1) {
98804 t = duk_bd_decode(bd, 5);
98805 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
98806 DUK_ASSERT(t <= 25);
98807 t = t + DUK_ASC_UC_A + (mode ^ 32);
98808 } else if (t == DUK__BITPACK_SWITCH) {
98809 mode = mode ^ 32;
98810 t = duk_bd_decode(bd, 5);
98811 DUK_ASSERT_DISABLE(t >= 0);
98812 DUK_ASSERT(t <= 25);
98813 t = t + DUK_ASC_UC_A + mode;
98814 } else if (t == DUK__BITPACK_EIGHTBIT) {
98815 t = duk_bd_decode(bd, 8);
98816 }
98817 out[i] = (duk_uint8_t) t;
98818 }
98819
98820 return len;
98821}
98822
98823/* automatic undefs */
98824#undef DUK__BITPACK_EIGHTBIT
98825#undef DUK__BITPACK_LETTER_LIMIT
98826#undef DUK__BITPACK_LOOKUP1
98827#undef DUK__BITPACK_LOOKUP2
98828#undef DUK__BITPACK_SWITCH
98829#undef DUK__BITPACK_SWITCH1
98830#undef DUK__BITPACK_UNUSED1
98831#line 1 "duk_util_bitencoder.c"
98832/*
98833 * Bitstream encoder.
98834 */
98835
98836/* #include duk_internal.h -> already included */
98837
98838DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
98839 duk_uint8_t tmp;
98840
98841 DUK_ASSERT(ctx != NULL);
98842 DUK_ASSERT(ctx->currbits < 8);
98843
98844 /* This limitation would be fixable but adds unnecessary complexity. */
98845 DUK_ASSERT(bits >= 1 && bits <= 24);
98846
98847 ctx->currval = (ctx->currval << bits) | data;
98848 ctx->currbits += bits;
98849
98850 while (ctx->currbits >= 8) {
98851 if (ctx->offset < ctx->length) {
98852 tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
98853 ctx->data[ctx->offset++] = tmp;
98854 } else {
98855 /* If buffer has been exhausted, truncate bitstream */
98856 ctx->truncated = 1;
98857 }
98858
98859 ctx->currbits -= 8;
98860 }
98861}
98862
98863DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
98864 duk_small_int_t npad;
98865
98866 DUK_ASSERT(ctx != NULL);
98867 DUK_ASSERT(ctx->currbits < 8);
98868
98869 npad = (duk_small_int_t) (8 - ctx->currbits);
98870 if (npad > 0) {
98871 duk_be_encode(ctx, 0, npad);
98872 }
98873 DUK_ASSERT(ctx->currbits == 0);
98874}
98875#line 1 "duk_util_bufwriter.c"
98876/*
98877 * Fast buffer writer with slack management.
98878 */
98879
98880/* #include duk_internal.h -> already included */
98881
98882/* XXX: Avoid duk_{memcmp,memmove}_unsafe() by imposing a minimum length of
98883 * >0 for the underlying dynamic buffer.
98884 */
98885
98886/*
98887 * Macro support functions (use only macros in calling code)
98888 */
98889
98890DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
98891 duk_uint8_t *p;
98892
98893 DUK_ASSERT(thr != NULL);
98894 DUK_ASSERT(bw_ctx != NULL);
98895 DUK_UNREF(thr);
98896
98897 /* 'p' might be NULL when the underlying buffer is zero size. If so,
98898 * the resulting pointers are not used unsafely.
98899 */
98900 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
98901 DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
98902 bw_ctx->p = p + curr_offset;
98903 bw_ctx->p_base = p;
98904 bw_ctx->p_limit = p + new_length;
98905}
98906
98907DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
98908 DUK_ASSERT(thr != NULL);
98909 DUK_ASSERT(bw_ctx != NULL);
98910 DUK_ASSERT(h_buf != NULL);
98911
98912 bw_ctx->buf = h_buf;
98913 duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
98914}
98915
98916DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
98917 DUK_ASSERT(thr != NULL);
98918 DUK_ASSERT(bw_ctx != NULL);
98919
98920 (void) duk_push_dynamic_buffer(thr, buf_size);
98921 bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
98922 DUK_ASSERT(bw_ctx->buf != NULL);
98923 duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
98924}
98925
98926/* Resize target buffer for requested size. Called by the macro only when the
98927 * fast path test (= there is space) fails.
98928 */
98929DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
98930 duk_size_t curr_off;
98931 duk_size_t add_sz;
98932 duk_size_t new_sz;
98933
98934 DUK_ASSERT(thr != NULL);
98935 DUK_ASSERT(bw_ctx != NULL);
98936
98937 /* We could do this operation without caller updating bw_ctx->ptr,
98938 * but by writing it back here we can share code better.
98939 */
98940
98941 curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
98942 add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD;
98943 new_sz = curr_off + sz + add_sz;
98944 if (DUK_UNLIKELY(new_sz < curr_off)) {
98945 /* overflow */
98946 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
98947 DUK_WO_NORETURN(return NULL;);
98948 }
98949#if 0 /* for manual torture testing: tight allocation, useful with valgrind */
98950 new_sz = curr_off + sz;
98951#endif
98952
98953 /* This is important to ensure dynamic buffer data pointer is not
98954 * NULL (which is possible if buffer size is zero), which in turn
98955 * causes portability issues with e.g. memmove() and memcpy().
98956 */
98957 DUK_ASSERT(new_sz >= 1);
98958
98959 DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
98960
98961 duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
98962 duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
98963 return bw_ctx->p;
98964}
98965
98966/* Make buffer compact, matching current written size. */
98967DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
98968 duk_size_t len;
98969
98970 DUK_ASSERT(thr != NULL);
98971 DUK_ASSERT(bw_ctx != NULL);
98972 DUK_UNREF(thr);
98973
98974 len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
98975 duk_hbuffer_resize(thr, bw_ctx->buf, len);
98976 duk__bw_update_ptrs(thr, bw_ctx, len, len);
98977}
98978
98979DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
98980 duk_uint8_t *p_base;
98981
98982 DUK_ASSERT(thr != NULL);
98983 DUK_ASSERT(bw != NULL);
98984 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
98985 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
98986 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
98987 DUK_UNREF(thr);
98988
98989 p_base = bw->p_base;
98990 duk_memcpy_unsafe((void *) bw->p,
98991 (const void *) (p_base + src_off),
98992 (size_t) len);
98993 bw->p += len;
98994}
98995
98996DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
98997 DUK_ASSERT(thr != NULL);
98998 DUK_ASSERT(bw != NULL);
98999 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
99000 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
99001 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
99002
99003 DUK_BW_ENSURE(thr, bw, len);
99004 duk_bw_write_raw_slice(thr, bw, src_off, len);
99005}
99006
99007DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) {
99008 duk_uint8_t *p_base;
99009 duk_size_t buf_sz, move_sz;
99010
99011 DUK_ASSERT(thr != NULL);
99012 DUK_ASSERT(bw != NULL);
99013 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
99014 DUK_ASSERT(buf != NULL);
99015 DUK_UNREF(thr);
99016
99017 p_base = bw->p_base;
99018 buf_sz = (duk_size_t) (bw->p - p_base); /* constrained by maximum buffer size */
99019 move_sz = buf_sz - dst_off;
99020
99021 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
99022 duk_memmove_unsafe((void *) (p_base + dst_off + len),
99023 (const void *) (p_base + dst_off),
99024 (size_t) move_sz);
99025 duk_memcpy_unsafe((void *) (p_base + dst_off),
99026 (const void *) buf,
99027 (size_t) len);
99028 bw->p += len;
99029}
99030
99031DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) {
99032 DUK_ASSERT(thr != NULL);
99033 DUK_ASSERT(bw != NULL);
99034 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
99035 DUK_ASSERT(buf != NULL);
99036
99037 DUK_BW_ENSURE(thr, bw, len);
99038 duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
99039}
99040
99041DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) {
99042 duk_uint8_t *p_base;
99043 duk_size_t buf_sz, move_sz;
99044
99045 DUK_ASSERT(thr != NULL);
99046 DUK_ASSERT(bw != NULL);
99047 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
99048 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
99049 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
99050 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
99051 DUK_UNREF(thr);
99052
99053 p_base = bw->p_base;
99054
99055 /* Don't support "straddled" source now. */
99056 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
99057
99058 if (dst_off <= src_off) {
99059 /* Target is before source. Source offset is expressed as
99060 * a "before change" offset. Account for the memmove.
99061 */
99062 src_off += len;
99063 }
99064
99065 buf_sz = (duk_size_t) (bw->p - p_base);
99066 move_sz = buf_sz - dst_off;
99067
99068 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
99069 duk_memmove_unsafe((void *) (p_base + dst_off + len),
99070 (const void *) (p_base + dst_off),
99071 (size_t) move_sz);
99072 duk_memcpy_unsafe((void *) (p_base + dst_off),
99073 (const void *) (p_base + src_off),
99074 (size_t) len);
99075 bw->p += len;
99076}
99077
99078DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) {
99079 DUK_ASSERT(thr != NULL);
99080 DUK_ASSERT(bw != NULL);
99081 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
99082 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
99083 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
99084 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
99085
99086 /* Don't support "straddled" source now. */
99087 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
99088
99089 DUK_BW_ENSURE(thr, bw, len);
99090 duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
99091}
99092
99093DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
99094 duk_uint8_t *p_base, *p_dst, *p_src;
99095 duk_size_t buf_sz, move_sz;
99096
99097 DUK_ASSERT(thr != NULL);
99098 DUK_ASSERT(bw != NULL);
99099 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
99100 DUK_UNREF(thr);
99101
99102 p_base = bw->p_base;
99103 buf_sz = (duk_size_t) (bw->p - p_base);
99104 move_sz = buf_sz - off;
99105 p_dst = p_base + off + len;
99106 p_src = p_base + off;
99107 duk_memmove_unsafe((void *) p_dst, (const void *) p_src, (size_t) move_sz);
99108 return p_src; /* point to start of 'reserved area' */
99109}
99110
99111DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
99112 DUK_ASSERT(thr != NULL);
99113 DUK_ASSERT(bw != NULL);
99114 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
99115
99116 DUK_BW_ENSURE(thr, bw, len);
99117 return duk_bw_insert_raw_area(thr, bw, off, len);
99118}
99119
99120DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
99121 duk_size_t move_sz;
99122
99123 duk_uint8_t *p_base;
99124 duk_uint8_t *p_src;
99125 duk_uint8_t *p_dst;
99126
99127 DUK_ASSERT(thr != NULL);
99128 DUK_ASSERT(bw != NULL);
99129 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
99130 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
99131 DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
99132 DUK_UNREF(thr);
99133
99134 p_base = bw->p_base;
99135 p_dst = p_base + off;
99136 p_src = p_dst + len;
99137 move_sz = (duk_size_t) (bw->p - p_src);
99138 duk_memmove_unsafe((void *) p_dst,
99139 (const void *) p_src,
99140 (size_t) move_sz);
99141 bw->p -= len;
99142}
99143
99144/*
99145 * Assertion helpers
99146 */
99147
99148#if defined(DUK_USE_ASSERTIONS)
99149DUK_INTERNAL void duk_bw_assert_valid(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
99150 DUK_UNREF(thr);
99151 DUK_ASSERT(bw_ctx != NULL);
99152 DUK_ASSERT(bw_ctx->buf != NULL);
99153 DUK_ASSERT((DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0) ||
99154 (bw_ctx->p != NULL &&
99155 bw_ctx->p_base != NULL &&
99156 bw_ctx->p_limit != NULL &&
99157 bw_ctx->p_limit >= bw_ctx->p_base &&
99158 bw_ctx->p >= bw_ctx->p_base &&
99159 bw_ctx->p <= bw_ctx->p_limit));
99160}
99161#endif
99162#line 1 "duk_util_cast.c"
99163/*
99164 * Cast helpers.
99165 *
99166 * C99+ coercion is challenging portability-wise because out-of-range casts
99167 * may invoke implementation defined or even undefined behavior. See e.g.
99168 * http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer.
99169 *
99170 * Provide explicit cast helpers which try to avoid implementation defined
99171 * or undefined behavior. These helpers can then be simplified in the vast
99172 * majority of cases where the implementation defined or undefined behavior
99173 * is not problematic.
99174 */
99175
99176/* #include duk_internal.h -> already included */
99177
99178/* Portable double-to-integer cast which avoids undefined behavior and avoids
99179 * relying on fmin(), fmax(), or other intrinsics. Out-of-range results are
99180 * not assumed by caller, but here value is clamped, NaN converts to minval.
99181 */
99182#define DUK__DOUBLE_INT_CAST1(tname,minval,maxval) do { \
99183 if (DUK_LIKELY(x >= (duk_double_t) (minval))) { \
99184 DUK_ASSERT(!DUK_ISNAN(x)); \
99185 if (DUK_LIKELY(x <= (duk_double_t) (maxval))) { \
99186 return (tname) x; \
99187 } else { \
99188 return (tname) (maxval); \
99189 } \
99190 } else { \
99191 /* NaN or below minval. Since we don't care about the result \
99192 * for out-of-range values, just return the minimum value for \
99193 * both. \
99194 */ \
99195 return (tname) (minval); \
99196 } \
99197 } while (0)
99198
99199/* Rely on specific NaN behavior for duk_double_{fmin,fmax}(): if either
99200 * argument is a NaN, return the second argument. This avoids a
99201 * NaN-to-integer cast which is undefined behavior.
99202 */
99203#define DUK__DOUBLE_INT_CAST2(tname,minval,maxval) do { \
99204 return (tname) duk_double_fmin(duk_double_fmax(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
99205 } while (0)
99206
99207/* Another solution which doesn't need C99+ behavior for fmin() and fmax(). */
99208#define DUK__DOUBLE_INT_CAST3(tname,minval,maxval) do { \
99209 if (DUK_ISNAN(x)) { \
99210 /* 0 or any other value is fine. */ \
99211 return (tname) 0; \
99212 } else \
99213 return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
99214 } \
99215 } while (0)
99216
99217/* C99+ solution: relies on specific fmin() and fmax() behavior in C99: if
99218 * one argument is NaN but the other isn't, the non-NaN argument is returned.
99219 * Because the limits are non-NaN values, explicit NaN check is not needed.
99220 * This may not work on all legacy platforms, and also doesn't seem to inline
99221 * the fmin() and fmax() calls (unless one uses -ffast-math which we don't
99222 * support).
99223 */
99224#define DUK__DOUBLE_INT_CAST4(tname,minval,maxval) do { \
99225 return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
99226 } while (0)
99227
99228DUK_INTERNAL duk_int_t duk_double_to_int_t(duk_double_t x) {
99229#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99230 /* Real world solution: almost any practical platform will provide
99231 * an integer value without any guarantees what it is (which is fine).
99232 */
99233 return (duk_int_t) x;
99234#else
99235 DUK__DOUBLE_INT_CAST1(duk_int_t, DUK_INT_MIN, DUK_INT_MAX);
99236#endif
99237}
99238
99239DUK_INTERNAL duk_uint_t duk_double_to_uint_t(duk_double_t x) {
99240#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99241 return (duk_uint_t) x;
99242#else
99243 DUK__DOUBLE_INT_CAST1(duk_uint_t, DUK_UINT_MIN, DUK_UINT_MAX);
99244#endif
99245}
99246
99247DUK_INTERNAL duk_int32_t duk_double_to_int32_t(duk_double_t x) {
99248#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99249 return (duk_int32_t) x;
99250#else
99251 DUK__DOUBLE_INT_CAST1(duk_int32_t, DUK_INT32_MIN, DUK_INT32_MAX);
99252#endif
99253}
99254
99255DUK_INTERNAL duk_uint32_t duk_double_to_uint32_t(duk_double_t x) {
99256#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99257 return (duk_uint32_t) x;
99258#else
99259 DUK__DOUBLE_INT_CAST1(duk_uint32_t, DUK_UINT32_MIN, DUK_UINT32_MAX);
99260#endif
99261}
99262
99263/* Largest IEEE double that doesn't round to infinity in the default rounding
99264 * mode. The exact midpoint between (1 - 2^(-24)) * 2^128 and 2^128 rounds to
99265 * infinity, at least on x64. This number is one double unit below that
99266 * midpoint. See misc/float_cast.c.
99267 */
99268#define DUK__FLOAT_ROUND_LIMIT 340282356779733623858607532500980858880.0
99269
99270/* Maximum IEEE float. Double-to-float conversion above this would be out of
99271 * range and thus technically undefined behavior.
99272 */
99273#define DUK__FLOAT_MAX 340282346638528859811704183484516925440.0
99274
99275DUK_INTERNAL duk_float_t duk_double_to_float_t(duk_double_t x) {
99276 /* Even a double-to-float cast is technically undefined behavior if
99277 * the double is out-of-range. C99 Section 6.3.1.5:
99278 *
99279 * If the value being converted is in the range of values that can
99280 * be represented but cannot be represented exactly, the result is
99281 * either the nearest higher or nearest lower representable value,
99282 * chosen in an implementation-defined manner. If the value being
99283 * converted is outside the range of values that can be represented,
99284 * the behavior is undefined.
99285 */
99286#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99287 return (duk_float_t) x;
99288#else
99289 duk_double_t t;
99290
99291 t = DUK_FABS(x);
99292 DUK_ASSERT((DUK_ISNAN(x) && DUK_ISNAN(t)) ||
99293 (!DUK_ISNAN(x) && !DUK_ISNAN(t)));
99294
99295 if (DUK_LIKELY(t <= DUK__FLOAT_MAX)) {
99296 /* Standard in-range case, try to get here with a minimum
99297 * number of checks and branches.
99298 */
99299 DUK_ASSERT(!DUK_ISNAN(x));
99300 return (duk_float_t) x;
99301 } else if (t <= DUK__FLOAT_ROUND_LIMIT) {
99302 /* Out-of-range, but rounds to min/max float. */
99303 DUK_ASSERT(!DUK_ISNAN(x));
99304 if (x < 0.0) {
99305 return (duk_float_t) -DUK__FLOAT_MAX;
99306 } else {
99307 return (duk_float_t) DUK__FLOAT_MAX;
99308 }
99309 } else if (DUK_ISNAN(x)) {
99310 /* Assumes double NaN -> float NaN considered "in range". */
99311 DUK_ASSERT(DUK_ISNAN(x));
99312 return (duk_float_t) x;
99313 } else {
99314 /* Out-of-range, rounds to +/- Infinity. */
99315 if (x < 0.0) {
99316 return (duk_float_t) -DUK_DOUBLE_INFINITY;
99317 } else {
99318 return (duk_float_t) DUK_DOUBLE_INFINITY;
99319 }
99320 }
99321#endif
99322}
99323
99324/* automatic undefs */
99325#undef DUK__DOUBLE_INT_CAST1
99326#undef DUK__DOUBLE_INT_CAST2
99327#undef DUK__DOUBLE_INT_CAST3
99328#undef DUK__DOUBLE_INT_CAST4
99329#undef DUK__FLOAT_MAX
99330#undef DUK__FLOAT_ROUND_LIMIT
99331#line 1 "duk_util_double.c"
99332/*
99333 * IEEE double helpers.
99334 */
99335
99336/* #include duk_internal.h -> already included */
99337
99338DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
99339 duk_double_union du;
99340 du.d = x;
99341 return DUK_DBLUNION_IS_ANYINF(&du);
99342}
99343
99344DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
99345 duk_double_union du;
99346 du.d = x;
99347 return DUK_DBLUNION_IS_POSINF(&du);
99348}
99349
99350DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
99351 duk_double_union du;
99352 du.d = x;
99353 return DUK_DBLUNION_IS_NEGINF(&du);
99354}
99355
99356DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
99357 duk_double_union du;
99358 du.d = x;
99359 /* Assumes we're dealing with a Duktape internal NaN which is
99360 * NaN normalized if duk_tval requires it.
99361 */
99362 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
99363 return DUK_DBLUNION_IS_NAN(&du);
99364}
99365
99366DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
99367 duk_double_union du;
99368 du.d = x;
99369 /* Assumes we're dealing with a Duktape internal NaN which is
99370 * NaN normalized if duk_tval requires it.
99371 */
99372 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
99373 return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
99374}
99375
99376DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
99377 duk_double_union du;
99378 du.d = x;
99379 /* If exponent is 0x7FF the argument is either a NaN or an
99380 * infinity. We don't need to check any other fields.
99381 */
99382#if defined(DUK_USE_64BIT_OPS)
99383#if defined(DUK_USE_DOUBLE_ME)
99384 return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
99385#else
99386 return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
99387#endif
99388#else
99389 return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
99390#endif
99391}
99392
99393DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
99394 duk_double_union du;
99395#if defined(DUK_USE_64BIT_OPS)
99396 duk_uint64_t t;
99397#else
99398 duk_uint32_t t;
99399#endif
99400 du.d = x;
99401#if defined(DUK_USE_64BIT_OPS)
99402#if defined(DUK_USE_DOUBLE_ME)
99403 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
99404 if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
99405 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
99406 return t == 0;
99407 }
99408 if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
99409 return 1;
99410 }
99411#else
99412 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
99413 if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
99414 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
99415 return t == 0;
99416 }
99417 if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
99418 return 1;
99419 }
99420#endif
99421#else
99422 t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
99423 if (t == 0x00000000UL) {
99424 return DUK_DBLUNION_IS_ANYZERO(&du);
99425 }
99426 if (t == 0x7ff00000UL) {
99427 return 1;
99428 }
99429#endif
99430 return 0;
99431}
99432
99433DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
99434 duk_double_union du;
99435 du.d = x;
99436 return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
99437}
99438
99439DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
99440 /* XXX: optimize */
99441 duk_small_uint_t s = duk_double_signbit(x);
99442 x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
99443 if (s) {
99444 x = -x;
99445 }
99446 return x;
99447}
99448
99449DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
99450 duk_double_union du1;
99451 duk_double_union du2;
99452 du1.d = x;
99453 du2.d = y;
99454
99455 return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
99456}
99457
99458DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
99459 /* Doesn't replicate fmin() behavior exactly: for fmin() if one
99460 * argument is a NaN, the other argument should be returned.
99461 * Duktape doesn't rely on this behavior so the replacement can
99462 * be simplified.
99463 */
99464 return (x < y ? x : y);
99465}
99466
99467DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
99468 /* Doesn't replicate fmax() behavior exactly: for fmax() if one
99469 * argument is a NaN, the other argument should be returned.
99470 * Duktape doesn't rely on this behavior so the replacement can
99471 * be simplified.
99472 */
99473 return (x > y ? x : y);
99474}
99475
99476DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) {
99477 return !duk_double_is_nan_or_inf(x);
99478}
99479
99480DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) {
99481 if (duk_double_is_nan_or_inf(x)) {
99482 return 0;
99483 } else {
99484 return duk_double_equals(duk_js_tointeger_number(x), x);
99485 }
99486}
99487
99488DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) {
99489 /* >>> 2**53-1
99490 * 9007199254740991
99491 */
99492 return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0;
99493}
99494
99495/* Check whether a duk_double_t is a whole number in the 32-bit range (reject
99496 * negative zero), and if so, return a duk_int32_t.
99497 * For compiler use: don't allow negative zero as it will cause trouble with
99498 * LDINT+LDINTX, positive zero is OK.
99499 */
99500DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
99501 duk_int32_t t;
99502
99503 t = duk_double_to_int32_t(x);
99504 if (!duk_double_equals((duk_double_t) t, x)) {
99505 return 0;
99506 }
99507 if (t == 0) {
99508 duk_double_union du;
99509 du.d = x;
99510 if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
99511 return 0;
99512 }
99513 }
99514 *ival = t;
99515 return 1;
99516}
99517
99518/* Check whether a duk_double_t is a whole number in the 32-bit range, and if
99519 * so, return a duk_int32_t.
99520 */
99521DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
99522 duk_int32_t t;
99523
99524 t = duk_double_to_int32_t(x);
99525 if (!duk_double_equals((duk_double_t) t, x)) {
99526 return 0;
99527 }
99528 *ival = t;
99529 return 1;
99530}
99531
99532/* Division: division by zero is undefined behavior (and may in fact trap)
99533 * so it needs special handling for portability.
99534 */
99535
99536DUK_INTERNAL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y) {
99537#if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99538 if (DUK_UNLIKELY(duk_double_equals(y, 0.0) != 0)) {
99539 /* In C99+ division by zero is undefined behavior so
99540 * avoid it entirely. Hopefully the compiler is
99541 * smart enough to avoid emitting any actual code
99542 * because almost all practical platforms behave as
99543 * expected.
99544 */
99545 if (x > 0.0) {
99546 if (DUK_SIGNBIT(y)) {
99547 return -DUK_DOUBLE_INFINITY;
99548 } else {
99549 return DUK_DOUBLE_INFINITY;
99550 }
99551 } else if (x < 0.0) {
99552 if (DUK_SIGNBIT(y)) {
99553 return DUK_DOUBLE_INFINITY;
99554 } else {
99555 return -DUK_DOUBLE_INFINITY;
99556 }
99557 } else {
99558 /* +/- 0, NaN */
99559 return DUK_DOUBLE_NAN;
99560 }
99561 }
99562#endif
99563
99564 return x / y;
99565}
99566
99567/* Double and float byteorder changes. */
99568
99569DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_little(duk_double_union *u) {
99570#if defined(DUK_USE_DOUBLE_LE)
99571 /* HGFEDCBA -> HGFEDCBA */
99572 DUK_UNREF(u);
99573#elif defined(DUK_USE_DOUBLE_ME)
99574 duk_uint32_t a, b;
99575
99576 /* DCBAHGFE -> HGFEDCBA */
99577 a = u->ui[0];
99578 b = u->ui[1];
99579 u->ui[0] = b;
99580 u->ui[1] = a;
99581#elif defined(DUK_USE_DOUBLE_BE)
99582 /* ABCDEFGH -> HGFEDCBA */
99583#if defined(DUK_USE_64BIT_OPS)
99584 u->ull[0] = DUK_BSWAP64(u->ull[0]);
99585#else
99586 duk_uint32_t a, b;
99587
99588 a = u->ui[0];
99589 b = u->ui[1];
99590 u->ui[0] = DUK_BSWAP32(b);
99591 u->ui[1] = DUK_BSWAP32(a);
99592#endif
99593#else
99594#error internal error
99595#endif
99596}
99597
99598DUK_INTERNAL DUK_INLINE void duk_dblunion_little_to_host(duk_double_union *u) {
99599 duk_dblunion_host_to_little(u);
99600}
99601
99602DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_big(duk_double_union *u) {
99603#if defined(DUK_USE_DOUBLE_LE)
99604 /* HGFEDCBA -> ABCDEFGH */
99605#if defined(DUK_USE_64BIT_OPS)
99606 u->ull[0] = DUK_BSWAP64(u->ull[0]);
99607#else
99608 duk_uint32_t a, b;
99609
99610 a = u->ui[0];
99611 b = u->ui[1];
99612 u->ui[0] = DUK_BSWAP32(b);
99613 u->ui[1] = DUK_BSWAP32(a);
99614#endif
99615#elif defined(DUK_USE_DOUBLE_ME)
99616 duk_uint32_t a, b;
99617
99618 /* DCBAHGFE -> ABCDEFGH */
99619 a = u->ui[0];
99620 b = u->ui[1];
99621 u->ui[0] = DUK_BSWAP32(a);
99622 u->ui[1] = DUK_BSWAP32(b);
99623#elif defined(DUK_USE_DOUBLE_BE)
99624 /* ABCDEFGH -> ABCDEFGH */
99625 DUK_UNREF(u);
99626#else
99627#error internal error
99628#endif
99629}
99630
99631DUK_INTERNAL DUK_INLINE void duk_dblunion_big_to_host(duk_double_union *u) {
99632 duk_dblunion_host_to_big(u);
99633}
99634
99635DUK_INTERNAL DUK_INLINE void duk_fltunion_host_to_big(duk_float_union *u) {
99636#if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME)
99637 /* DCBA -> ABCD */
99638 u->ui[0] = DUK_BSWAP32(u->ui[0]);
99639#elif defined(DUK_USE_DOUBLE_BE)
99640 /* ABCD -> ABCD */
99641 DUK_UNREF(u);
99642#else
99643#error internal error
99644#endif
99645}
99646
99647DUK_INTERNAL DUK_INLINE void duk_fltunion_big_to_host(duk_float_union *u) {
99648 duk_fltunion_host_to_big(u);
99649}
99650
99651/* Comparison: ensures comparison operates on exactly correct types, avoiding
99652 * some floating point comparison pitfalls (e.g. atan2() assertions failed on
99653 * -m32 with direct comparison, even with explicit casts).
99654 */
99655#if defined(DUK_USE_GCC_PRAGMAS)
99656#pragma GCC diagnostic push
99657#pragma GCC diagnostic ignored "-Wfloat-equal"
99658#elif defined(DUK_USE_CLANG_PRAGMAS)
99659#pragma clang diagnostic push
99660#pragma clang diagnostic ignored "-Wfloat-equal"
99661#endif
99662
99663DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y) {
99664 return x == y;
99665}
99666
99667DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y) {
99668 return x == y;
99669}
99670#if defined(DUK_USE_GCC_PRAGMAS)
99671#pragma GCC diagnostic pop
99672#elif defined(DUK_USE_CLANG_PRAGMAS)
99673#pragma clang diagnostic pop
99674#endif
99675#line 1 "duk_util_hashbytes.c"
99676/*
99677 * Hash function duk_util_hashbytes().
99678 *
99679 * Currently, 32-bit MurmurHash2.
99680 *
99681 * Don't rely on specific hash values; hash function may be endianness
99682 * dependent, for instance.
99683 */
99684
99685/* #include duk_internal.h -> already included */
99686
99687#if defined(DUK_USE_STRHASH_DENSE)
99688/* 'magic' constants for Murmurhash2 */
99689#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
99690#define DUK__MAGIC_R 24
99691
99692DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
99693 duk_uint32_t h = seed ^ ((duk_uint32_t) len);
99694
99695 while (len >= 4) {
99696 /* Portability workaround is required for platforms without
99697 * unaligned access. The replacement code emulates little
99698 * endian access even on big endian architectures, which is
99699 * OK as long as it is consistent for a build.
99700 */
99701#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
99702 duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
99703#else
99704 duk_uint32_t k = ((duk_uint32_t) data[0]) |
99705 (((duk_uint32_t) data[1]) << 8) |
99706 (((duk_uint32_t) data[2]) << 16) |
99707 (((duk_uint32_t) data[3]) << 24);
99708#endif
99709
99710 k *= DUK__MAGIC_M;
99711 k ^= k >> DUK__MAGIC_R;
99712 k *= DUK__MAGIC_M;
99713 h *= DUK__MAGIC_M;
99714 h ^= k;
99715 data += 4;
99716 len -= 4;
99717 }
99718
99719 switch (len) {
99720 case 3: h ^= data[2] << 16;
99721 case 2: h ^= data[1] << 8;
99722 case 1: h ^= data[0];
99723 h *= DUK__MAGIC_M;
99724 }
99725
99726 h ^= h >> 13;
99727 h *= DUK__MAGIC_M;
99728 h ^= h >> 15;
99729
99730 return h;
99731}
99732#endif /* DUK_USE_STRHASH_DENSE */
99733
99734/* automatic undefs */
99735#undef DUK__MAGIC_M
99736#undef DUK__MAGIC_R
99737#line 1 "duk_util_memory.c"
99738/*
99739 * Memory utils.
99740 */
99741
99742/* #include duk_internal.h -> already included */
99743
99744#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
99745DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
99746 DUK_ASSERT(s1 != NULL || len == 0U);
99747 DUK_ASSERT(s2 != NULL || len == 0U);
99748 return DUK_MEMCMP(s1, s2, (size_t) len);
99749}
99750
99751DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
99752 DUK_ASSERT(s1 != NULL);
99753 DUK_ASSERT(s2 != NULL);
99754 return DUK_MEMCMP(s1, s2, (size_t) len);
99755}
99756#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
99757DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
99758 DUK_ASSERT(s1 != NULL || len == 0U);
99759 DUK_ASSERT(s2 != NULL || len == 0U);
99760 if (DUK_UNLIKELY(len == 0U)) {
99761 return 0;
99762 }
99763 DUK_ASSERT(s1 != NULL);
99764 DUK_ASSERT(s2 != NULL);
99765 return duk_memcmp(s1, s2, len);
99766}
99767
99768DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
99769 DUK_ASSERT(s1 != NULL);
99770 DUK_ASSERT(s2 != NULL);
99771 return DUK_MEMCMP(s1, s2, (size_t) len);
99772}
99773#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
99774#line 1 "duk_util_tinyrandom.c"
99775/*
99776 * A tiny random number generator used for Math.random() and other internals.
99777 *
99778 * Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c
99779 * with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c.
99780 *
99781 * Low memory targets and targets without 64-bit types use a slightly smaller
99782 * (but slower) algorithm by Adi Shamir:
99783 * http://www.woodmann.com/forum/archive/index.php/t-3100.html.
99784 *
99785 */
99786
99787/* #include duk_internal.h -> already included */
99788
99789#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
99790
99791#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
99792#define DUK__RANDOM_SHAMIR3OP
99793#else
99794#define DUK__RANDOM_XOROSHIRO128PLUS
99795#endif
99796
99797#if defined(DUK__RANDOM_SHAMIR3OP)
99798#define DUK__UPDATE_RND(rnd) do { \
99799 (rnd) += ((rnd) * (rnd)) | 0x05UL; \
99800 (rnd) = ((rnd) & 0xffffffffUL); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
99801 } while (0)
99802
99803#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
99804
99805DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
99806 DUK_UNREF(thr); /* Nothing now. */
99807}
99808
99809DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
99810 duk_double_t t;
99811 duk_small_int_t n;
99812 duk_uint32_t rnd;
99813
99814 rnd = thr->heap->rnd_state;
99815
99816 n = 53; /* enough to cover the whole mantissa */
99817 t = 0.0;
99818
99819 do {
99820 DUK__UPDATE_RND(rnd);
99821 t += DUK__RND_BIT(rnd);
99822 t /= 2.0;
99823 } while (--n);
99824
99825 thr->heap->rnd_state = rnd;
99826
99827 DUK_ASSERT(t >= (duk_double_t) 0.0);
99828 DUK_ASSERT(t < (duk_double_t) 1.0);
99829
99830 return t;
99831}
99832#endif /* DUK__RANDOM_SHAMIR3OP */
99833
99834#if defined(DUK__RANDOM_XOROSHIRO128PLUS)
99835DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) {
99836 duk_uint64_t z;
99837 z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15));
99838 z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9);
99839 z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB);
99840 return z ^ (z >> 31U);
99841}
99842
99843DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) {
99844 return (x << k) | (x >> (64U - k));
99845}
99846
99847DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) {
99848 duk_uint64_t s0;
99849 duk_uint64_t s1;
99850 duk_uint64_t res;
99851
99852 s0 = s[0];
99853 s1 = s[1];
99854 res = s0 + s1;
99855 s1 ^= s0;
99856 s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U);
99857 s[1] = duk__rnd_rotl(s1, 36);
99858
99859 return res;
99860}
99861
99862DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
99863 duk_small_uint_t i;
99864 duk_uint64_t x;
99865
99866 /* Mix both halves of the initial seed with SplitMix64. The intent
99867 * is to ensure that very similar raw seeds (which is usually the case
99868 * because current seed is Date.now()) result in different xoroshiro128+
99869 * seeds.
99870 */
99871 x = thr->heap->rnd_state[0]; /* Only [0] is used as input here. */
99872 for (i = 0; i < 64; i++) {
99873 thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x); /* Keep last 2 values. */
99874 }
99875}
99876
99877DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
99878 duk_uint64_t v;
99879 duk_double_union du;
99880
99881 /* For big and little endian the integer and IEEE double byte order
99882 * is the same so a direct assignment works. For mixed endian the
99883 * 32-bit parts must be swapped.
99884 */
99885 v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
99886 du.ull[0] = v;
99887#if defined(DUK_USE_DOUBLE_ME)
99888 do {
99889 duk_uint32_t tmp;
99890 tmp = du.ui[0];
99891 du.ui[0] = du.ui[1];
99892 du.ui[1] = tmp;
99893 } while (0);
99894#endif
99895 return du.d - 1.0;
99896}
99897#endif /* DUK__RANDOM_XOROSHIRO128PLUS */
99898
99899#endif /* !DUK_USE_GET_RANDOM_DOUBLE */
99900
99901/* automatic undefs */
99902#undef DUK__RANDOM_SHAMIR3OP
99903#undef DUK__RANDOM_XOROSHIRO128PLUS
99904#undef DUK__RND_BIT
99905#undef DUK__UPDATE_RND
99906